[ghc-steering-committee] Proposal #631: Set program exit code by main return type, recommendation: accept something

Simon Peyton Jones simon.peytonjones at gmail.com
Mon Mar 4 11:13:50 UTC 2024


I am a little worried about breaking programs that end in an
innocent-looking `return 0`, just because some other languages like to end
programs with that phrase


The proposal specifies that such a program returns `ExitSuccess`, but adds
a warning. That seems OK to me; it does not break the program.

Oh -- maybe you mean that `return 1` means "return with exit code 1"
today.  Is that really true?  I don't think so.

Overall this proposal seems fine to me.  I'd be happy to see it done.

Simon

On Thu, 29 Feb 2024 at 12:38, Richard Eisenberg <reisenberg at janestreet.com>
wrote:

> I haven't followed this proposal closely. But couldn't we have a
> transition period toward this eventual goal? That is, introduce a new
> warning, on by default, if `main` returns anything other than `()`. That
> goes for a few releases. Then we require that the return type of main has
> an instance of ExitStatus.
>
> I'm not worried about changing the behavior of programs that have type IO
> ExitCode but expect the program to return 0 unconditionally; that's just
> begging for confusion. I am a little worried about breaking programs that
> end in an innocent-looking `return 0`, just because some other languages
> like to end programs with that phrase. So I'm not sure if we should have an
> instance ExitStatus Int (or instance ExitStatus Integer) -- but we probably
> should. If a program ends with `return 1`, the programmer probably wants
> the OS to return 1 as well.
>
> Richard
>
> On Thu, Feb 29, 2024 at 5:29 AM Arnaud Spiwack <arnaud.spiwack at tweag.io>
> wrote:
>
>> Dear all,
>>
>> Shea Levy proposes to do something with the values returned by `main`
>> https://github.com/ghc-proposals/ghc-proposals/pull/631 .
>>
>> The problem is that `main` is allowed to be of type `IO A` for any `A`.
>> And GHC will simply drop the value returned by `main`. Shea contends that
>> it's surprising. I agree that dropping a value without the compiler being
>> explicitly instructed to is surprising. But Shea says that when `A` is
>> `ExitCode` this is even more surprising. Namely `main :: IO ExitCode; main
>> = return $ Failure 1` actually terminates with exit code 0. And I doubt
>> that it's what anybody expects when reading the code.
>>
>> The proposal is simple, but I have a lot of comments on it. Sorry about
>> that…
>>
>> Now, this sort of proposal is tricky. When the current behaviour is
>> confusing, we want to change the default. But putting the new default
>> behind an extension doesn't really solve the fact that there's a trap. The
>> extension is, therefore, unlikely to be well tested before it becomes part
>> of the next language edition.
>>
>> Shea's main proposition doesn't actually use an extension though. He adds
>> a type class `ExitStatus`, and if `ExistStatus A`, then `main :: IO A` uses
>> the instance to determine the exit code based on the return value.
>>
>> The only change to the current behaviour is that `main :: IO ExitCode`
>> instead of always terminating with exit code 0 when returning now
>> terminates with the expected error code. The argument for not putting this
>> behind an extension is that virtually anybody affected by the change will
>> actually have the behaviour they were expecting. But maybe the argument
>> isn't strong enough (the changes may be more “interesting” if some library
>> exports some `ExistStatus` instance).
>>
>> This design of this proposal is inspired by Rust's design. I've asked our
>> Rust team, and they certainly seem to have internalised the idea of
>> returning an exit code. It really seems a pretty natural feature to have.
>> So I'm rather in favour of some flavour of the type class implementation.
>> Though have a look at the alternatives, where you'll find other approaches
>> such as restricting the type of `main` to unsurprising types.
>>
>> One caveat with respect to the main proposal: it is proposed that when no
>> `ExistStatus A` is found, then we drop the returned value like today. I
>> don't know that it's quite easy to implement this behaviour. But it can be
>> recovered by a catch-all overlapping instance, so maybe it's a better way
>> to specify the desired behaviour.
>>
>> --
>> Arnaud Spiwack
>> Director, Research at https://moduscreate.com and https://tweag.io.
>> _______________________________________________
>> ghc-steering-committee mailing list
>> ghc-steering-committee at haskell.org
>> https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
>>
> _______________________________________________
> ghc-steering-committee mailing list
> ghc-steering-committee at haskell.org
> https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-steering-committee/attachments/20240304/1e9ec1c1/attachment.html>


More information about the ghc-steering-committee mailing list