minor annoyance: main doesn't return a status to os

1282 views
Skip to first unread message

Johann Höchtl

unread,
Dec 20, 2012, 11:04:17 AM12/20/12
to golan...@googlegroups.com
I find myself rather often write

func main() {
   os.Exit(mymain())
}

because main doesn't return a status to the os. And calling os.Exit(status) in main is not a good idea as deferred functions wont fire. Much to late for a change?

minux

unread,
Dec 20, 2012, 1:23:08 PM12/20/12
to Johann Höchtl, golan...@googlegroups.com
I think the returned status is OS-specific, and so Go the language should not define its type
(Maybe some OS can only report 8-bit result while some other OS support arbitrary string
as program status, there is considerable differences between that; there might even be
environment that don't support returning status code or the concept of status code simply
doesn't exist)

I imagine some Plan 9 users might be disagree with the signature of os.Exit().

Johann Höchtl

unread,
Dec 20, 2012, 5:18:15 PM12/20/12
to minux, golan...@googlegroups.com
That may be the case. But package os is a compromise anyway and we have
os.Exit only taking ints right now. Extending main as in C to return an
int flag to the spawning process would help especially in the case of
small routines embedded in shell scripts.

Kyle Lemons

unread,
Dec 20, 2012, 5:29:25 PM12/20/12
to Johann Höchtl, minux, golang-nuts
What's wrong with just calling os.Exit with a nonzero code when you have a failure in main?




--



minux

unread,
Dec 20, 2012, 5:29:41 PM12/20/12
to Johann Höchtl, golan...@googlegroups.com
i think changing standard library has a lower cost compared to changing the
core language.

you will note the the language does a good amount of work to avoid architecture
or os dependencies. for example, even the lock is implemented in standard library
because it is highly architecture dependent (future architectures might use entirely
different form of locks or atomics, if that happens, we only need to revise the std.
lib., and the core language doesn't need to be changed.)

you can also feel this when you read the memory model docs, because for people
accustomed to programming on x86, some clauses of mem. model is simply crazy
or unreasonable, yet some architectures implementations do do those unreasonable
things to achieve better efficiency.

minux

unread,
Dec 20, 2012, 5:33:13 PM12/20/12
to Kyle Lemons, Johann Höchtl, golang-nuts

On Friday, December 21, 2012, Kyle Lemons wrote:
What's wrong with just calling os.Exit with a nonzero code when you have a failure in main?
i'd like to add that the go command itself uses code like that to
implement a localized atexit functionality.

Johann Höchtl

unread,
Dec 20, 2012, 5:56:26 PM12/20/12
to Kyle Lemons, golang-nuts, minux


Am 20.12.2012 23:29 schrieb "Kyle Lemons" <kev...@google.com>:
>
> What's wrong with just calling os.Exit with a nonzero code when you have a failure in main?
>

deferred calls will not fire

Andrew Gerrand

unread,
Dec 20, 2012, 6:04:17 PM12/20/12
to Johann Höchtl, Kyle Lemons, golang-nuts, minux
Say the signature of main is "func main() int", where the return value is the process exit code, and os.Exit doesn't exist.

What does a function that is not main do to exit the program? For example, flag.Parse calls os.Exit(2) if the flags are parsed incorrectly. Would you need to set up a deferred recover in main, and panic from flag.Parse? That has different semantics, though. Would you have flag.Parse return an error? But then you'd need to call flag.Usage and exit manually, which is inconvenient.

I suspect that whatever the proposed solution to this problem is, it will be more complicated than the status quo.

Andrew

Johann Höchtl

unread,
Dec 20, 2012, 6:16:32 PM12/20/12
to Andrew Gerrand, golang-nuts, Kyle Lemons, minux

I see the pattern / bigger underlying 'issue'. That might be the reason why there is no atexit too. Thinking about it I can't propose a better solution either.

yy

unread,
Dec 20, 2012, 6:53:30 PM12/20/12
to Johann Höchtl, golang-nuts
On 20 December 2012 17:04, Johann Höchtl <johann....@gmail.com> wrote:
I find myself rather often write

func main() {
   os.Exit(mymain())
}

(Maybe you already thought on this, but just in case.)

Another option, which probably is not a big improvement but may be simpler in some cases, is to defer os.Exit:

func main() {
    var exit int  // or exit := 0
    defer os.Exit(exit)
    // do whatever you want and set exit
}


--
- yiyus || JGL .

yy

unread,
Dec 20, 2012, 6:59:47 PM12/20/12
to Johann Höchtl, golang-nuts
On 21 December 2012 00:53, yy <yiyu...@gmail.com> wrote:

func main() {
    var exit int  // or exit := 0
    defer os.Exit(exit)
    // do whatever you want and set exit
}

Sorry. Of course, this won't work, because the arguments are evaluated when you call defer.

However, a function which takes a pointer may be useful:

func exit(e *int) {
    os.Exit(*e)
}

but, yeah, at that point is not an improvement at all. Sorry for the noise.

 

Jesse McNelis

unread,
Dec 20, 2012, 7:34:20 PM12/20/12
to yy, Johann Höchtl, golang-nuts
On Fri, Dec 21, 2012 at 10:59 AM, yy <yiyu...@gmail.com> wrote:
Sorry. Of course, this won't work, because the arguments are evaluated when you call defer.

However, a function which takes a pointer may be useful:

func exit(e *int) {
    os.Exit(*e)
}

func main() {
   ret := -1
   defer func(){os.Exit(ret)}
   ret = mymain()
   return
}

Although, this would exit before a panic could be printed, so if you don't want your panics disappearing you'd need to add a recover and check for the panic before running the os.Exit().




--
=====================
http://jessta.id.au

Sonia Keys

unread,
Dec 22, 2012, 8:12:37 AM12/22/12
to golan...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages