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

Adam Gundry adam at well-typed.com
Thu Mar 7 09:26:55 UTC 2024


I've added a comment to the GitHub thread 
(https://github.com/ghc-proposals/ghc-proposals/pull/631#issuecomment-1983060484) 
elaborating slightly on Richard's suggestion (albeit with an effectively 
indefinite transition period).

Adam


On 05/03/2024 08:52, Arnaud Spiwack wrote:
> This is Alternative 7.5 in the current version of the proposal 
> https://github.com/shlevy/ghc-proposals/blob/io-exitcode/proposals/0631-main-return-types.rst#75require-an-exitstatus-instance <https://github.com/shlevy/ghc-proposals/blob/io-exitcode/proposals/0631-main-return-types.rst#75require-an-exitstatus-instance> .
> 
> PS: I tend to agree with Richard that requiring an ExitStatus instance 
> is the preferable option. But food for thought for the proposal thread 
> when that conversation happens there: should that be gated behind an 
> extension? In which case it won't become the default before the next 
> language edition.
> 
> /Arnaud
> 
> On Mon, 4 Mar 2024 at 21:35, Simon Peyton Jones 
> <simon.peytonjones at gmail.com <mailto:simon.peytonjones at gmail.com>> wrote:
> 
>         I left out a key part of my last email -- apologies. I'm
>         floating a counter-proposal where we *require* an instance of
>         ExitStatus on the return type of `main`, with a transition
>         period. In contrast, my understanding of the proposal written is
>         that it would use such an instance if it exists, but issue a
>         warning if it doesn't, in perpetuity.
> 
> 
>     Ah  I had not realised that.
> 
>     But why?
> 
>     Rather than answer here (private to SC) why don't you put your
>     proposal on the discussion thread, say why, and invite feedback.
> 
>     Simon
> 
> 
>     On Mon, 4 Mar 2024 at 19:24, Richard Eisenberg
>     <reisenberg at janestreet.com <mailto:reisenberg at janestreet.com>> wrote:
> 
>         I left out a key part of my last email -- apologies. I'm
>         floating a counter-proposal where we *require* an instance of
>         ExitStatus on the return type of `main`, with a transition
>         period. In contrast, my understanding of the proposal written is
>         that it would use such an instance if it exists, but issue a
>         warning if it doesn't, in perpetuity.
> 
>         Richard
> 
>         On Mon, Mar 4, 2024 at 6:14 AM Simon Peyton Jones
>         <simon.peytonjones at gmail.com
>         <mailto:simon.peytonjones at gmail.com>> wrote:
> 
>                 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
>             <mailto: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
>                 <mailto: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 <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
>                     <https://moduscreate.com> and https://tweag.io
>                     <https://tweag.io>.


-- 
Adam Gundry, Haskell Consultant
Well-Typed LLP, https://www.well-typed.com/

Registered in England & Wales, OC335890
27 Old Gloucester Street, London WC1N 3AX, England



More information about the ghc-steering-committee mailing list