FAQ
Hi Go folks,

I've discussed this a bit off-list, but I figure it's best raised through
the appropriate channels. So, this compiles:

func foo() int {
for {
return 20;
}
return 10;
}

But this does not compile:

func foo() int {
for {
return 20;
}
}

The error is "function ends without a return statement".

That's back to front. The first one should compile, the second one should
fail with an "unreachable code" error. Obviously this code is trivial, but
I think "loop forever until a certain point, then exit" is a perfectly
valid coding pattern that should be properly supported.

(I've deliberately avoided a more common case that exhibits the same
problem—many people like to use if/else at the top level of a function, but
Go doesn't permit this when there's a return value. Discussion of that
example tends to devolve into an argument over style, whereas I'm
specifically concerned here about correctness.)

The explanation I've heard for this is:
1. Returning a value from a function is mandatory, and should be checked
identically by all Go implementations;
2. The definition is intentionally simple and straightforward: the last
statement in a function must be a return.

1 is great, but I think 2 is misguided. It is just not that hard to
strictly define reachability in a way that works correctly more often than
the current rule. There aren't a lot of different control structures
(good!) so it seems straightforward, unless I'm missing something.

Working through the structures listed
in http://golang.org/doc/effective_go.html#control-structures:
- If: body may not be executed, so following code is always reachable.
- If/else: following code is unreachable if both branches always exit.
- For (c-style or conditional): body may not be executed, so following
code is reachable.
- For (infinite loop): following code is unreachable unless there's a
reachable "break".
- Switch: if there's a default and all cases exit, following code is
unreachable.
- Panic: immediately following code is unreachable.
- Recover: unreachable if there's no opportunity for panic (no function
calls, I guess?)

Oops, forgot "return"! Well, I guess that one's pretty obvious. :)

I would suggest drawing the line at constant-folding, i.e. do *not* mandate
reachability analysis even for trivial expressions like "if false" or "for
true". The compiler *could* certainly do a lot of useful checking, but it
would be hard to ensure that all compilers do it identically.

So, what do you think? Is this change worth making to the language?

Iain

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • Patrick Mylund Nielsen at Feb 22, 2013 at 12:31 pm
    This is issue 65: https://code.google.com/p/go/issues/detail?id=65

    On Fri, Feb 22, 2013 at 1:21 PM, wrote:

    Hi Go folks,

    I've discussed this a bit off-list, but I figure it's best raised through
    the appropriate channels. So, this compiles:

    func foo() int {
    for {
    return 20;
    }
    return 10;
    }

    But this does not compile:

    func foo() int {
    for {
    return 20;
    }
    }

    The error is "function ends without a return statement".

    That's back to front. The first one should compile, the second one should
    fail with an "unreachable code" error. Obviously this code is trivial, but
    I think "loop forever until a certain point, then exit" is a perfectly
    valid coding pattern that should be properly supported.

    (I've deliberately avoided a more common case that exhibits the same
    problem—many people like to use if/else at the top level of a function, but
    Go doesn't permit this when there's a return value. Discussion of that
    example tends to devolve into an argument over style, whereas I'm
    specifically concerned here about correctness.)

    The explanation I've heard for this is:
    1. Returning a value from a function is mandatory, and should be checked
    identically by all Go implementations;
    2. The definition is intentionally simple and straightforward: the last
    statement in a function must be a return.

    1 is great, but I think 2 is misguided. It is just not that hard to
    strictly define reachability in a way that works correctly more often than
    the current rule. There aren't a lot of different control structures
    (good!) so it seems straightforward, unless I'm missing something.

    Working through the structures listed in
    http://golang.org/doc/effective_go.html#control-structures:
    - If: body may not be executed, so following code is always reachable.
    - If/else: following code is unreachable if both branches always exit.
    - For (c-style or conditional): body may not be executed, so following
    code is reachable.
    - For (infinite loop): following code is unreachable unless there's a
    reachable "break".
    - Switch: if there's a default and all cases exit, following code is
    unreachable.
    - Panic: immediately following code is unreachable.
    - Recover: unreachable if there's no opportunity for panic (no function
    calls, I guess?)

    Oops, forgot "return"! Well, I guess that one's pretty obvious. :)

    I would suggest drawing the line at constant-folding, i.e. do *not*
    mandate reachability analysis even for trivial expressions like "if false"
    or "for true". The compiler *could* certainly do a lot of useful checking,
    but it would be hard to ensure that all compilers do it identically.

    So, what do you think? Is this change worth making to the language?

    Iain

    --
    You received this message because you are subscribed to the Google Groups
    "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 22, 2013 at 12:38 pm

    On Fri, Feb 22, 2013 at 12:31 PM, Patrick Mylund Nielsen wrote:
    This is issue 65: https://code.google.com/p/go/issues/detail?id=65
    Aha, thanks! I searched this list for "reachability" and didn't see
    anything that looked relevant.

    I note that discussion on that bug has mostly focused on that if/else
    style debate I talked about. I'll go ahead and add a note on for{}.

    Iain

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 22, 2013 at 12:51 pm

    Iain Merrick wrote:
    Patrick Mylund Nielsen wrote:
    Aha, thanks! I searched this list for "reachability" and didn't see
    anything that looked relevant.

    I note that discussion on that bug has mostly focused on that if/else
    style debate I talked about. I'll go ahead and add a note on for{}.
    Oops, except I don't have bug-commenting access. Anyway, I really hope
    there's progress on this, as I think it's an unfortunate blemish on the
    language. I'm concerned that it has been sidelined into a mere style
    debate, and that the core team might have decided that the current version
    is correct, but hopefully that's not the case.

    Cheers,

    Iain

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nate Finch at Feb 22, 2013 at 6:07 pm
    Check out this thread:

    https://groups.google.com/forum/#!topic/golang-nuts/D-mmT10VBEA

    I noted that Go doesn't give errors about unreachable code, and several
    people said that's on purpose. *shrug* I think it would be better to make
    them errors, but I'm not in charge ;)


    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 22, 2013 at 6:15 pm
    Interesting! Although if you were follow my suggested implementation,
    the compiler intentionally wouldn't fold out "true" and "false" so
    things like "if false { ... }" would still be allowed.

    In general I really like the strict errors / no warnings approach, but
    there's a tricky tradeoff between enforcing high-quality production
    code, and allowing some elbow room for hacking purposes. I'd
    definitely like a "non-strict" mode I can use during development which
    turns some errors into warnings, but I imagine that has been pitched
    before and rejected.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Patrick Mylund Nielsen at Feb 22, 2013 at 6:22 pm
    Weird. The examples given in the thread show why being able to use consts
    for variables that are known at compile-time to cut out sections of code is
    very useful.

    These two issues are unrelated, IMO.

    On Fri, Feb 22, 2013 at 7:07 PM, Nate Finch wrote:

    Check out this thread:

    https://groups.google.com/forum/#!topic/golang-nuts/D-mmT10VBEA

    I noted that Go doesn't give errors about unreachable code, and several
    people said that's on purpose. *shrug* I think it would be better to make
    them errors, but I'm not in charge ;)

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 22, 2013 at 6:19 pm
    It's important to distinguish between optimizations (the more the
    better! as long as they're safe), and static checks.

    The checks should always cause compile errors, and all compilers
    should do them in exactly the same way, to ensure all code is
    portable. That means they need to be very rigorously specified up
    front, which puts an upper limit on how complex they can be. (I think
    they put the bar way too low in the case of reachability, though.)

    If your compiler is able to do some really clever analysis that
    identifies some huge swathe of code as unreachable, that's great, but
    it shouldn't be a compile error. Maybe a warning. :)

    Iain

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nate Finch at Feb 22, 2013 at 8:38 pm
    He was talking about an error that he though should actually be an error
    about reachability. The title of the thread is reachability analysis. My
    thread was about lack of errors for reachability. I can't imagine how it's
    not pertinent, even if the two examples are (very) slightly different.
    On Friday, February 22, 2013 1:15:51 PM UTC-5, Patrick Mylund Nielsen wrote:

    Weird. The examples given in the thread show why being able to use consts
    for variables that are known at compile-time to cut out sections of code is
    very useful.

    These two issues are unrelated, IMO.


    On Fri, Feb 22, 2013 at 7:07 PM, Nate Finch <nate....@gmail.com<javascript:>
    wrote:
    Check out this thread:

    https://groups.google.com/forum/#!topic/golang-nuts/D-mmT10VBEA

    I noted that Go doesn't give errors about unreachable code, and several
    people said that's on purpose. *shrug* I think it would be better to make
    them errors, but I'm not in charge ;)

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • John Asmuth at Feb 22, 2013 at 6:29 pm
    The general problem of identifying unreachable code is insolvable. The best
    we can do is look for some special cases. Then it's an issue of deciding
    where to draw the line. "Right at the beginning" is a perfectly valid place
    to draw it. :)
    On Friday, February 22, 2013 1:07:02 PM UTC-5, Nate Finch wrote:

    Check out this thread:

    https://groups.google.com/forum/#!topic/golang-nuts/D-mmT10VBEA

    I noted that Go doesn't give errors about unreachable code, and several
    people said that's on purpose. *shrug* I think it would be better to make
    them errors, but I'm not in charge ;)

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 22, 2013 at 6:42 pm
    It's rather pessimistic to say that's "the best we can do"! Of course
    you can't make it perfect but you can at least pick the blatant
    low-hanging fruit.

    I think Scheme is a good comparison -- the specification of when tail
    recursion can be applied (and *must* be applied) isn't trivial, but
    they went through the trouble of figuring it out, and that reaps some
    important benefits.

    For the case of reachability in Go, the benefits are 1) not requiring
    clearly incorrect code to satisfy the compiler (e.g. my original
    example), 2) allowing other code to compile which is clearly correct,
    and most importantly 3) maybe catching some real accidental
    occurrences of unreachable code. I admit I don't know how common that
    last one is, though!

    The major practical impact of the current approach is that it freezes
    into language canon a specific style decision (neither good nor bad in
    itself, I'd say) to ban top-level if/else blocks. That's an
    unfortunate red herring -- it's a non-issue, both styles ought to be
    permitted. I feel like somebody must have preferred the no-else style,
    and decided on that basis that the "all functions must end in a
    return" rule is a good one, but that's faulty logic.

    Iain

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • John Asmuth at Feb 22, 2013 at 6:47 pm

    On Friday, February 22, 2013 1:42:39 PM UTC-5, Iain Merrick wrote:
    It's rather pessimistic to say that's "the best we can do"! Of course
    you can't make it perfect but you can at least pick the blatant
    low-hanging fruit.
    Pessimistic is the wrong word. Special cases are literally the only thing
    we can do.

    I feel like somebody must have preferred the no-else style,
    and decided on that basis that the "all functions must end in a
    return" rule is a good one, but that's faulty logic.
    I think it's really unlikely that this was the thought process.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nigel Tao at Feb 22, 2013 at 11:36 pm

    On Sat, Feb 23, 2013 at 5:42 AM, Iain Merrick wrote:
    The major practical impact of the current approach is that it freezes
    into language canon a specific style decision (neither good nor bad in
    itself, I'd say) to ban top-level if/else blocks. That's an
    unfortunate red herring -- it's a non-issue, both styles ought to be
    permitted.
    I would disagree that both styles ought to be permitted. Large
    projects have a style guide for a reason. Unfortunately, different
    C/C++ projects have different style guides, even though they're all
    C/C++. Large C/C++ projects (like web browsers, or Google servers)
    depend on other, third party C/C++ projects (libjpeg, openssl, sqlite,
    etc.), and crossing a project boundary requires a mental context
    switch. Go has only one particular style, largely enforced by gofmt,
    but not solely defined by gofmt. Newcomers to Go invariably grumble
    about how they dislike some Go style decisions. I did too, when I was
    new. But I'm happy to lose the tabs vs spaces war in order to end the
    tabs vs spaces war. I would say that writing

    if b {
    return x
    }
    return y

    instead of if/else is just another aspect of Go's particular style.
    It's enforced by gc and gccgo at the top level, but as an experienced
    Go programmer, I would also expect to read and write that style at
    lower levels.

    A similar story is that you can't put the opening curly bracket on its
    own line. This code

    if b
    {
    return x
    }
    return y

    won't compile. It won't compile because of a simple lexical rule that
    allowed us to remove semi-colons from a C-like language. A top-level
    if/else is similarly a compile-time error as a consequence of a simple
    syntactic rule. I'm not convinced that making the rules more
    complicated is worth the cost.


    P.S. you missed "select" in your list of control structures.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nigel Tao at Feb 23, 2013 at 4:08 am

    On Sat, Feb 23, 2013 at 10:36 AM, Nigel Tao wrote:
    P.S. you missed "select" in your list of control structures.
    Oh, one more: "goto". As always, the spec (http://golang.org/ref/spec)
    has the definitive list of statements, not "Effective Go".

    You mentioned Scheme as a precedent for non-trivial language
    specification. IIUC, without tail recursion optimization, idiomatic
    Scheme can have showstopping performance or resource requirements.
    That is not the case here, and so I think that specifying Go
    reachability in non-trivial technical English is less obviously of
    benefit.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 24, 2013 at 10:12 pm

    On Saturday, 23 February 2013 04:08:43 UTC, Nigel Tao wrote:

    As always, the spec (http://golang.org/ref/spec)
    has the definitive list of statements, not "Effective Go".
    Hmm, I can't actually find the "function must end in return statement" rule
    in the spec! But amusingly, there is an example of the wrong if/else style:
    http://golang.org/ref/spec#If_statements

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jan Mercl at Feb 25, 2013 at 12:05 am

    On Sun, Feb 24, 2013 at 11:12 PM, Iain Merrick wrote:
    Hmm, I can't actually find the "function must end in return statement" rule
    in the spec! But amusingly, there is an example of the wrong if/else style:
    http://golang.org/ref/spec#If_statements
    That's not an example of wrong/correct/any style, but an example of
    what (some of the [other]) forms of the if-statement the language
    (grammar) permits. Especially, the presence of the simple statement,
    the else-if chaining and the else clause per se.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nigel Tao at Feb 22, 2013 at 11:47 pm

    On Sat, Feb 23, 2013 at 5:42 AM, Iain Merrick wrote:
    For the case of reachability in Go, the benefits are 1) not requiring
    clearly incorrect code to satisfy the compiler (e.g. my original
    example),
    I forgot to mention that any change to the set of valid Go programs
    should consider the Go 1 backwards compatibility guarantees at
    http://golang.org/doc/go1compat.html, and that a Go 2.0 isn't going to
    happen any time soon.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 23, 2013 at 12:13 am
    Oh, sure, I realise that! That's why I wanted to get some opinions. I'm
    totally willing to help implement this if need be (though I'm not at all
    familiar with the code) but only if there's agreement that it's worthwhile.

    Your general point about the importance of consistent style is of course
    correct, but in this case I still say it's a red herring. I assume the
    compiler doesn't enforce the no-else style if there isn't a return value,
    for example.
    On 22 Feb 2013 23:47, "Nigel Tao" wrote:
    On Sat, Feb 23, 2013 at 5:42 AM, Iain Merrick wrote:
    For the case of reachability in Go, the benefits are 1) not requiring
    clearly incorrect code to satisfy the compiler (e.g. my original
    example),
    I forgot to mention that any change to the set of valid Go programs
    should consider the Go 1 backwards compatibility guarantees at
    http://golang.org/doc/go1compat.html, and that a Go 2.0 isn't going to
    happen any time soon.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 23, 2013 at 12:19 am
    Thought I'd better check that assumption. :)

    http://play.golang.org/p/K5sBY58vgX
    On 23 Feb 2013 00:13, "Iain Merrick" wrote:

    Oh, sure, I realise that! That's why I wanted to get some opinions. I'm
    totally willing to help implement this if need be (though I'm not at all
    familiar with the code) but only if there's agreement that it's worthwhile.

    Your general point about the importance of consistent style is of course
    correct, but in this case I still say it's a red herring. I assume the
    compiler doesn't enforce the no-else style if there isn't a return value,
    for example.
    On 22 Feb 2013 23:47, "Nigel Tao" wrote:

    On Sat, Feb 23, 2013 at 5:42 AM, Iain Merrick <iain.merrick@gmail.com>
    wrote:
    For the case of reachability in Go, the benefits are 1) not requiring
    clearly incorrect code to satisfy the compiler (e.g. my original
    example),
    I forgot to mention that any change to the set of valid Go programs
    should consider the Go 1 backwards compatibility guarantees at
    http://golang.org/doc/go1compat.html, and that a Go 2.0 isn't going to
    happen any time soon.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 23, 2013 at 12:21 am
    Er, actually, forget that, it doesn't show anything useful after all. Too
    late to be thinking about this stuff, evidently.
    On 23 Feb 2013 00:19, "Iain Merrick" wrote:

    Thought I'd better check that assumption. :)

    http://play.golang.org/p/K5sBY58vgX
    On 23 Feb 2013 00:13, "Iain Merrick" wrote:

    Oh, sure, I realise that! That's why I wanted to get some opinions. I'm
    totally willing to help implement this if need be (though I'm not at all
    familiar with the code) but only if there's agreement that it's worthwhile.

    Your general point about the importance of consistent style is of course
    correct, but in this case I still say it's a red herring. I assume the
    compiler doesn't enforce the no-else style if there isn't a return value,
    for example.
    On 22 Feb 2013 23:47, "Nigel Tao" wrote:

    On Sat, Feb 23, 2013 at 5:42 AM, Iain Merrick <iain.merrick@gmail.com>
    wrote:
    For the case of reachability in Go, the benefits are 1) not requiring
    clearly incorrect code to satisfy the compiler (e.g. my original
    example),
    I forgot to mention that any change to the set of valid Go programs
    should consider the Go 1 backwards compatibility guarantees at
    http://golang.org/doc/go1compat.html, and that a Go 2.0 isn't going to
    happen any time soon.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nigel Tao at Feb 23, 2013 at 1:21 am

    On Sat, Feb 23, 2013 at 11:13 AM, Iain Merrick wrote:
    Oh, sure, I realise that! That's why I wanted to get some opinions. I'm
    totally willing to help implement this if need be (though I'm not at all
    familiar with the code) but only if there's agreement that it's worthwhile.
    To clarify, there are a couple of potential changes. One is to
    disallow programs like

    func foo() int {
    for {
    return 20
    }
    return 10
    }

    We can't do this and maintain Go 1 compatibility.

    Two is to allow programs like

    func foo() int {
    for {
    return 20
    }
    }

    and

    func foo() int {
    if b {
    return 1
    } else {
    return 2
    }
    }

    We could do this and maintain Go 1 compatibility. In my experience in
    writing Go, mentoring newcomers and reviewing their code, this is a
    somewhat FAQ but in practice it's not a big deal. In the first case,
    add a panic("unreachable") and move on. In the second case, I think it
    falls under style, and in practice, you delete the "else" and move on.
    This if-without-else style is consistent with lots of Go code that
    looks like

    x, err := foo()
    if err != nil {
    return err
    }
    doMoreWith(x)

    It may be survivor bias, but experienced Go programmers don't seem to
    care about this as much as newcomers to Go.

    Your general point about the importance of consistent style is of course
    correct, but in this case I still say it's a red herring. I assume the
    compiler doesn't enforce the no-else style if there isn't a return value,
    for example.
    Style is more than whether or not the compiler accepts. For example,
    naming the method receiver "this" or "self" is valid Go but considered
    non-idiomatic style.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Kamil Kisiel at Feb 23, 2013 at 3:28 am

    On Friday, February 22, 2013 5:21:32 PM UTC-8, Nigel Tao wrote:
    On Sat, Feb 23, 2013 at 11:13 AM, Iain Merrick wrote:
    Oh, sure, I realise that! That's why I wanted to get some opinions. I'm
    totally willing to help implement this if need be (though I'm not at all
    familiar with the code) but only if there's agreement that it's
    worthwhile.

    To clarify, there are a couple of potential changes. One is to
    disallow programs like

    func foo() int {
    for {
    return 20
    }
    return 10
    }

    We can't do this and maintain Go 1 compatibility.

    Two is to allow programs like

    func foo() int {
    for {
    return 20
    }
    }

    and

    func foo() int {
    if b {
    return 1
    } else {
    return 2
    }
    }

    We could do this and maintain Go 1 compatibility. In my experience in
    writing Go, mentoring newcomers and reviewing their code, this is a
    somewhat FAQ but in practice it's not a big deal. In the first case,
    add a panic("unreachable") and move on. In the second case, I think it
    falls under style, and in practice, you delete the "else" and move on.
    This if-without-else style is consistent with lots of Go code that
    looks like

    x, err := foo()
    if err != nil {
    return err
    }
    doMoreWith(x)

    It may be survivor bias, but experienced Go programmers don't seem to
    care about this as much as newcomers to Go.

    Your general point about the importance of consistent style is of course
    correct, but in this case I still say it's a red herring. I assume the
    compiler doesn't enforce the no-else style if there isn't a return value,
    for example.
    Style is more than whether or not the compiler accepts. For example,
    naming the method receiver "this" or "self" is valid Go but considered
    non-idiomatic style.
    I would definitely prefer two never happened. It is slightly inconvenient
    to an extra line or two here or there, until you get used to it. However it
    goes well with what I consider to be one of Go's biggest strengths: low
    cognitive load when reading code. I like being able to look at any point in
    the code and figure out what's going on without having to keep all of the
    context in my head. It's the same reason I prefer explicit returns even
    with named return values.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 25, 2013 at 11:23 am

    On Saturday, 23 February 2013 01:21:32 UTC, Nigel Tao wrote:

    To clarify, there are a couple of potential changes. One is to
    disallow programs like

    func foo() int {
    for {
    return 20
    }
    return 10
    }

    We can't do this and maintain Go 1 compatibility.

    Two is to allow programs like

    func foo() int {
    for {
    return 20
    }
    }

    and

    func foo() int {
    if b {
    return 1
    } else {
    return 2
    }
    }

    We could do this and maintain Go 1 compatibility. [...]
    It may be survivor bias, but experienced Go programmers don't seem to
    care about this as much as newcomers to Go.
    Yep, that's a good summary of the impact. In terms of underlying rules that
    lead to those examples, my specific proposal was:
    1. Define the exit criteria for each control flow construct.
    2. Require all non-void functions to return a value.
    3. Ban code that is trivially unreachable (i.e. no optimization steps
    needed)

    Item 3 is what breaks Go v1 compatibility. But it occurs to me that we
    could just postpone that item, and still do 1 and 2.

    The spec doesn't say anything about item 1 right now, but I strongly
    believe it's worth doing if you're serious about supporting third-party
    implementations of the same language.

    If we implement just items 1 and 2, that doesn't break existing code, but
    allows some new code to compile:

    func foo() int {
    for {
    return 20
    }
    }

    func bar() int {
    if b {
    return 1
    } else {
    return 2
    }
    }

    Now, bar() is non-idiomatic as you've pointed it. But if we're already
    doing simple reachability analysis, we can have gofmt tidy this up
    automatically! It's a completely safe transformation -- just hoist the
    "else" branch to the top level in situations where the "if" branch always
    exits. That seems much friendlier than a compile error.

    To summarize, here's my new revised v1-compatible proposal:
    1. Define the exit criteria for each control flow construct.
    2. Require all non-void functions to return a value.
    3. Extend gofmt to remove unnecessary "else" statements.

    Iain

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jan Mercl at Feb 25, 2013 at 11:41 am

    On Mon, Feb 25, 2013 at 12:23 PM, Iain Merrick wrote:
    To summarize, here's my new revised v1-compatible proposal:
    1. Define the exit criteria for each control flow construct.
    2. Require all non-void functions to return a value.
    In short: I think you're solving an almost non-problem at the cost of
    making the specs unnecessarily more complex.
    3. Extend gofmt to remove unnecessary "else" statements.
    That would be IMHO very unfortunate. The 'fmt' means 'format' [white
    space] not 'else-style' or whatever other legal language construct.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 25, 2013 at 11:51 am

    On Monday, 25 February 2013 11:40:15 UTC, Jan Mercl wrote:
    On Mon, Feb 25, 2013 at 12:23 PM, Iain Merrick wrote:
    To summarize, here's my new revised v1-compatible proposal:
    1. Define the exit criteria for each control flow construct.
    2. Require all non-void functions to return a value.
    In short: I think you're solving an almost non-problem at the cost of
    making the specs unnecessarily more complex.
    Yeah, I realise the impact seems small. It just strikes me as a little
    rough corner on the language, one that's worth sanding off to bring it up
    to par with Java, C#, etc. And I'm offering to do the work.

    To your second point, I think the specs will have to become more complex in
    any case if you want to support third-party implementations.
    3. Extend gofmt to remove unnecessary "else" statements.

    That would be IMHO very unfortunate. The 'fmt' means 'format' [white
    space] not 'else-style' or whatever other legal language construct.
    Maybe a "go fix" rule or something, then. This is my attempt to find a
    compromise between the style dispute and the correctness dispute. You've
    frozen into the language a broken correctness rule that enforces that style
    rule in some cases, but not in others.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jan Mercl at Feb 25, 2013 at 12:01 pm

    On Mon, Feb 25, 2013 at 12:51 PM, Iain Merrick wrote:
    You've
    frozen into the language a broken correctness rule that enforces that style
    rule in some cases, but not in others.
    I'm not sure if we're talk about the same thing, but I don't think
    this "rule" is/ever was part of the specs.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • David Symonds at Feb 25, 2013 at 12:20 pm

    On Mon, Feb 25, 2013 at 10:51 PM, Iain Merrick wrote:

    To your second point, I think the specs will have to become more complex in
    any case if you want to support third-party implementations.
    Please point out concrete places in the spec that can't be reasonably
    used to construct a compatible Go implementation. Everything is
    supposed to be covered to a good enough level of detail.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 25, 2013 at 2:50 pm

    David Symonds wrote:

    Iain Merrick wrote:
    To your second point, I think the specs will have to become more complex in
    any case if you want to support third-party implementations.
    Please point out concrete places in the spec that can't be reasonably
    used to construct a compatible Go implementation. Everything is
    supposed to be covered to a good enough level of detail.
    I can't find anything in the spec that defines the current compiler
    behaviour, with the "function ends without a return statement" error. I'd
    expect to see that in one of these places:

    http://golang.org/ref/spec#Blocks
    http://golang.org/ref/spec#Function_declarations
    http://golang.org/ref/spec#Function_literals
    http://golang.org/ref/spec#Return_statements

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 25, 2013 at 2:59 pm
    Here's the Java definition of reachability:
    http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21

    It's already reasonably straightforward, and the final third is a
    non-normative discussion of constant folding. I think a Go version of the
    mandatory bits would be simpler, because you have fewer control structures,
    and no need to special case "while(true)".

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Russ Cox at Feb 25, 2013 at 3:14 pm
    The spec does not define what it means for a function to be missing a
    return. We need to do that. I have some ideas and some analysis of existing
    code, which I will post when I have some more time. Right now there are
    higher-priority things to work on.

    Russ

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jesse McNelis at Feb 25, 2013 at 12:07 pm

    On Mon, Feb 25, 2013 at 10:40 PM, Jan Mercl wrote:

    That would be IMHO very unfortunate. The 'fmt' means 'format' [white
    space] not 'else-style' or whatever other legal language construct.

    gofmt does have a -s option to simplify the code that makes non-whitespace
    changes to the code.

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

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jan Mercl at Feb 25, 2013 at 12:19 pm

    On Mon, Feb 25, 2013 at 1:06 PM, Jesse McNelis wrote:
    On Mon, Feb 25, 2013 at 10:40 PM, Jan Mercl wrote:

    That would be IMHO very unfortunate. The 'fmt' means 'format' [white
    space] not 'else-style' or whatever other legal language construct.

    gofmt does have a -s option to simplify the code that makes non-whitespace
    changes to the code.
    Ah, you're right, I forgot it. I don't know if it rewrites flow
    control(? - it's not trivial, I believe). I thought that it can only,
    e.g. remove unnecessary parenthesis etc.? Not sure actually, I don't
    think I've really used this specific gofmt's feature.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Kevin Gillette at Feb 25, 2013 at 9:59 pm

    On Monday, February 25, 2013 4:23:10 AM UTC-7, Iain Merrick wrote:

    3. Ban code that is trivially unreachable (i.e. no optimization steps
    needed)

    const debug = false
    if debug {
    // ...
    }

    That is one of the few "trivially unreachable" cases, and you certainly
    don't want to ban that.

    if true /* testing */ && someCond() {
    // ...
    } else if someOtherCond() {
    // ...
    } else {
    // ...
    }

    In this case, a quick hack is used to test a potentially rare case, which
    is a valid development/debugging strategy -- if the compiler refuses to
    proceed because the else-if and the else are both trivially determined as
    unreachable, you're taking tools out of the hands of the developer, and
    possibly taking frustrated developers out of the community.

    switch runtime.GOOS {
    case "windows":
    // ...
    case "darwin":
    // ...
    default:
    // ...
    }

    Two out of the three cases are trivially detectable as dead-code for any
    given platform-specific compile, but obviously it should not be banned.
    There will be cases where platform-specific code is short enough (possibly
    just one line per platform) to just keep it all in the same file, rather
    than reorganizing code to have specialized versions of functions in
    platform-specific files. Banning dead code would mean you'd have to add a
    lot of counter-complexity to the compiler, including white-listing
    expressions that should be allowed.

    Yes, there are unreachable cases that are trivially detectable, but you
    absolutely cannot make any assumptions about the triviality/legitimacy of
    dead-code without at least first solving the halting problem.

    Now, bar() is non-idiomatic as you've pointed it. But if we're already
    doing simple reachability analysis, we can have gofmt tidy this up
    automatically! It's a completely safe transformation -- just hoist the
    "else" branch to the top level in situations where the "if" branch always
    exits. That seems much friendlier than a compile error.

    3. Extend gofmt to remove unnecessary "else" statements.
    A few things: gofmt doesn't parse the code, it only does a lexing pass.
    With a small state-machine, it would be sufficient information to collapse
    else blocks at the end of a function, and perhaps migrate end-of-func
    return statements within a loop to the end of a function, putting a break
    in their place (though this gets notoriously difficult when multiple loops
    or switch statements in loops are involved -- sometimes a goto works best,
    or a break statement taking a label, or an end-of-func panic). gofmt is
    absolutely not suitable for handling dead-code, since that would require
    semantic analysis which can't be done on the syntactic level.

    All that said, gofmt is used in a variety of non-obvious, automatic ways:
    for example, many of us have our editors configured to gofmt our code every
    time the file is written, and many of us save compulsively and edit
    sporadically -- what may appear to be at the end of a function when gofmt
    is run is not necessarily at the end of function in the programmer's mind,
    and structural transforms like you suggest can be surprising, and go
    unnoticed during editing, producing unexpected bugs (collapsing an else
    statement is really only guaranteed safe when it *stays* at the end of a
    function). If you're seriously proposing this, it has to be a non-default
    behavior that gets its own, new, option switch -- otherwise you'll do a
    whole lot more harm than good.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 25, 2013 at 10:09 pm

    On Monday, 25 February 2013 21:59:22 UTC, Kevin Gillette wrote:
    On Monday, February 25, 2013 4:23:10 AM UTC-7, Iain Merrick wrote:

    3. Ban code that is trivially unreachable (i.e. no optimization steps
    needed)

    const debug = false
    if debug {
    // ...
    }

    That is one of the few "trivially unreachable" cases, and you certainly
    don't want to ban that.
    As I said in that mail a few lines above the snippet you quoted, I was just
    re-stating my original proposal, before amending it. Sorry if I was
    unclear; I was aiming for clarity!

    3. Extend gofmt to remove unnecessary "else" statements.
    A few things: gofmt doesn't parse the code, it only does a lexing pass.
    Ah, okay! I wasn't aware of that. The kind of analysis I'm talking about is
    very simple, but it does need some real parsing, not just lexing.

    [...]
    If you're seriously proposing this, it has to be a non-default behavior
    that gets its own, new, option switch -- otherwise you'll do a whole lot
    more harm than good.
    Sure, wherever it fits best into the toolchain. (go fix? go vet?) The
    overall goal would be to relax the rules to allow some correct code to
    compile (i.e. don't require spurious return statements), while at the same
    time encouraging and/or enforcing the team's preferred style for those
    top-level if/else statements.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Iain Merrick at Feb 25, 2013 at 10:14 pm
    Also, I didn't suggested banning "if debug {...}" code. Right at the start
    of this thread I said:
    I would suggest drawing the line at constant-folding, i.e. do *not*
    mandate reachability analysis even for trivial expressions like "if false"
    or "for true".

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jan Mercl at Feb 25, 2013 at 10:15 pm

    On Mon, Feb 25, 2013 at 10:59 PM, Kevin Gillette wrote:
    A few things: gofmt doesn't parse the code, it only does a lexing pass.
    I'm lazy to check (sorry), but I don't believe it. I think it's not
    possible to do what gofmt does w/o an AST.

    -j

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nigel Tao at Feb 26, 2013 at 12:47 am

    On Tue, Feb 26, 2013 at 9:14 AM, Jan Mercl wrote:
    On Mon, Feb 25, 2013 at 10:59 PM, Kevin Gillette
    wrote:
    A few things: gofmt doesn't parse the code, it only does a lexing pass.
    I'm lazy to check (sorry), but I don't believe it. I think it's not
    possible to do what gofmt does w/o an AST.
    gofmt does build an AST. For example,
    http://golang.org/src/cmd/gofmt/gofmt.go imports go/ast and go/parser
    and calls parser.ParseFile.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.
  • Rémy Oudompheng at Feb 22, 2013 at 12:34 pm

    On 2013/2/22 wrote:
    Working through the structures listed in
    http://golang.org/doc/effective_go.html#control-structures:
    - If: body may not be executed, so following code is always reachable.
    - If/else: following code is unreachable if both branches always exit.
    - For (c-style or conditional): body may not be executed, so following code
    is reachable.
    - For (infinite loop): following code is unreachable unless there's a
    reachable "break".
    - Switch: if there's a default and all cases exit, following code is
    unreachable.
    - Panic: immediately following code is unreachable.
    - Recover: unreachable if there's no opportunity for panic (no function
    calls, I guess?)
    Recover is not a control structure, and has no effect on control flow.
    It shouldn't be on your list.

    Rémy.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedFeb 22, '13 at 12:30p
activeFeb 26, '13 at 12:47a
posts38
users12
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase