In this basic-cli PR we replace Process.exit 1 with Task.err 1, what do you think about making this Task.exitWithErr (which calls Task.err 1)?
This prevents the use of what may appear to be a magical constant (1) to those unfamiliar with exit codes
would it always use 1?
I always struggle with figuring out which error code to pick, to be honest...I'm not sure what all the conventions out there are :sweat_smile:
2 could be used for user errors like invalid options or missing arguments but it seems like it has basically no impact if 1 was returned in case of a missing argument. I would still allow users to call Task.err myExitCode for the people that want that.
I would do Task.exitWithCode <errorCode> or Task.errWithCode <errorCode> and just make it more explicit even though it just would call Task.err
Yeah, those may be best, I think they would help prevent confusion about the I32 in main's type
something to keep in mind is that in the future, Task will be a builtin module, so that would have to be moved
what about having an opaque ExitCode type, and then a helper function with the type I32 -> Task * ExitCode
so then the type of main would be main : Task {} ExitCode
I like it :)
You still could do Process.exit and make it do nothing but return a Task.err? but yeah, making exit code opaque works too
It would improve error messages too I assume. When people try to return a task to main without handling the error case. Actually will this prevent just using stdout.line and mean we always need additional logic to handle erroes?
no, because Stdout.line returns Task {} *
so in the same way that it currently works with I32, it would work with an opaque type, because * unifies with anything! :smiley:
That said, stdin and maybe also stdout should return errors given they have a few failure cases. Instead the app would panic in rust and crash
So we would actually want it not to return *
So the error would need to be handled if we ever update that
For stdin it is more clear cut given you need to know when an inputted file ends. For stdout, still probably nice to know if the output pipe is closed (not exactly sure other error cases)
errWithCode : I32 -> Task * ExitCode
Can I add it like this to basic-cli/Task.roc @Richard Feldman?
I think we should figure out a different module for it to go in
because if we put it in Task now, we're just going to have to move it once Task becomes a builtin - so might as well figure out where it should go now instead :big_smile:
Process.roc is gone in the latest basic-cli but we can bring it back and put errWithCode into it.
seems reasonable! :thumbs_up:
Process.ExitCode makes sense to me too
:thinking: might someone expect a function with the name Process.errWithCode to immediately exit?
How about Process.errorExit?
Process.exitWithCode maybe?
exitWithCode does not really show that an error ocurred
Last updated: Jun 16 2026 at 16:19 UTC