FAQ
I was refactoring some code recently and was surprised to discover that
this doesn't compile.

------------------------------------------------------------
package main

import "fmt"

func f() {
         fmt.Printf("f\n")
         return
}

func g() {
         fmt.Printf("g\n")
         return f()
}

func main() {
         g()
}
------------------------------------------------------------

Giving these errors

./void_func.go:12: f() used as value
./void_func.go:12: too many arguments to return

This idiom does work in a lot of languages (eg C and Python).

------------------------------------------------------------
#include <stdio.h>

void f(void) {
     printf("f\n");
     return;
}

void g(void) {
     printf("g\n");
     return f();
}

int main(void) {
     g();
     return 0;
}
------------------------------------------------------------

I suspect it works in C and Python because functions always return
something though that may be void/None whereas go functions really can
return nothing.

It would be neat if it could be made to work in Go. It means that if
you refactor functions it makes it much more regular, as in "return
f()" will always work regardless of the type signature of g().

Here is the actual example that set me off thinking about this

func Error500(w http.ResponseWriter, message string) {
         w.WriteHeader(500)
         fmt.Fprint(w, message)
}

func Request(w http.ResponseWriter, r *http.Request) {
         // Stuff
         if !somethingOk {
                 Error500(w, "Something not OK")
                 return
         }
         // Compute more stuff
         if !somethingElseOk {
                 Error500(w, "Something else not OK")
                 return
         }
         // Stuff
}

The two calls to Error500 would look much neater like this in my
opinion as the intention of tail calling Error500 is expressed better.

func Request(w http.ResponseWriter, r *http.Request) {
         if !somethingOk {
                 return Error500(w, "Something not OK")
         }
         // Compute more stuff
         if !somethingElseOk {
                 return Error500(w, "Something else not OK")
         }
         // Stuff
}

--
Nick Craig-Wood <[email protected]> -- http://www.craig-wood.com/nick

--
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 [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Search Discussions

  • David DENG at Jul 11, 2013 at 3:48 pm
    Even in C/C++, I seldom write in this way.

    David
    On Thursday, July 11, 2013 11:12:42 PM UTC+8, Nick Craig-Wood wrote:

    I was refactoring some code recently and was surprised to discover that
    this doesn't compile.

    ------------------------------------------------------------
    package main

    import "fmt"

    func f() {
    fmt.Printf("f\n")
    return
    }

    func g() {
    fmt.Printf("g\n")
    return f()
    }

    func main() {
    g()
    }
    ------------------------------------------------------------

    Giving these errors

    ./void_func.go:12: f() used as value
    ./void_func.go:12: too many arguments to return

    This idiom does work in a lot of languages (eg C and Python).

    ------------------------------------------------------------
    #include <stdio.h>

    void f(void) {
    printf("f\n");
    return;
    }

    void g(void) {
    printf("g\n");
    return f();
    }

    int main(void) {
    g();
    return 0;
    }
    ------------------------------------------------------------

    I suspect it works in C and Python because functions always return
    something though that may be void/None whereas go functions really can
    return nothing.

    It would be neat if it could be made to work in Go. It means that if
    you refactor functions it makes it much more regular, as in "return
    f()" will always work regardless of the type signature of g().

    Here is the actual example that set me off thinking about this

    func Error500(w http.ResponseWriter, message string) {
    w.WriteHeader(500)
    fmt.Fprint(w, message)
    }

    func Request(w http.ResponseWriter, r *http.Request) {
    // Stuff
    if !somethingOk {
    Error500(w, "Something not OK")
    return
    }
    // Compute more stuff
    if !somethingElseOk {
    Error500(w, "Something else not OK")
    return
    }
    // Stuff
    }

    The two calls to Error500 would look much neater like this in my
    opinion as the intention of tail calling Error500 is expressed better.

    func Request(w http.ResponseWriter, r *http.Request) {
    if !somethingOk {
    return Error500(w, "Something not OK")
    }
    // Compute more stuff
    if !somethingElseOk {
    return Error500(w, "Something else not OK")
    }
    // Stuff
    }

    --
    Nick Craig-Wood <[email protected] <javascript:>> --
    http://www.craig-wood.com/nick
    --
    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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jan Mercl at Jul 11, 2013 at 4:46 pm

    On Thu, Jul 11, 2013 at 5:12 PM, Nick Craig-Wood wrote:
    I was refactoring some code recently and was surprised to discover that
    this doesn't compile.
    I'm surprised it surprises you.
    ------------------------------------------------------------
    package main

    import "fmt"

    func f() {
    fmt.Printf("f\n")
    return
    }

    func g() {
    fmt.Printf("g\n")
    return f()
    }

    func main() {
    g()
    }
    ------------------------------------------------------------

    Giving these errors

    ./void_func.go:12: f() used as value
    ./void_func.go:12: too many arguments to return
    Correctly reported errors.
    This idiom does work in a lot of languages (eg C and Python).

    ------------------------------------------------------------
    #include <stdio.h>

    void f(void) {
    printf("f\n");
    return;
    }

    void g(void) {
    printf("g\n");
    return f();
    }

    int main(void) {
    g();
    return 0;
    }
    ------------------------------------------------------------
    It surprises me that gcc -Wall accepts the code w/o warnings as it is
    IMO a bad coding style.
    It would be neat if it could be made to work in Go. It means that if
    you refactor functions it makes it much more regular, as in "return
    f()" will always work regardless of the type signature of g().
    Sorry, but that IMHO a terrible idea. The return statement syntax,
    where its owning function has a return value, is 'return
    <expression>'. How can a void function be used as an value? Why to
    allow silent bugs when a coder forgets to declare that a function
    returns something? Why to allow even more silent bugs where the
    returns-nothing-function is used as a (part of an) expression?

    Go is very strict on forgetting to declare, or use things or mix
    different types etc. This "It would be neat" thing is IMHO completely
    incompatible with the rest of the language.

    I see no advantage in this, only major disadvantages.

    -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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nick Craig-Wood at Jul 11, 2013 at 5:23 pm

    On 11/07/13 17:46, Jan Mercl wrote:
    On Thu, Jul 11, 2013 at 5:12 PM, Nick Craig-Wood wrote:
    I was refactoring some code recently and was surprised to discover that
    this doesn't compile.
    I'm surprised it surprises you.
    It surprises me because I've used that idiom in other languages, thats all!
    Giving these errors

    ./void_func.go:12: f() used as value
    ./void_func.go:12: too many arguments to return
    Correctly reported errors.
    Those two errors say `f()` isn't a value, and return doesn't need a
    value. Since f() isn't a value why can't we put it after return which
    doesn't need one?

    In my opinion the above makes Go slightly irregular, whereas C is
    perfectly regular in this respect.
    It surprises me that gcc -Wall accepts the code w/o warnings as it is
    IMO a bad coding style.
    I'm afraid both the C standard and gcc disagree with you here ;-)
    Sorry, but that IMHO a terrible idea. The return statement syntax,
    where its owning function has a return value, is 'return
    <expression>'. How can a void function be used as an value? Why to
    allow silent bugs when a coder forgets to declare that a function
    returns something? Why to allow even more silent bugs where the
    returns-nothing-function is used as a (part of an) expression?
    There will be no silent bugs.

    Go checks that the arguments to return match the list of types in the
    function declaration. All I'm proposing is that the missing case - an
    empty list of types - is allowed too.

    --
    Nick Craig-Wood <[email protected]> -- http://www.craig-wood.com/nick

    --
    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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Tamás Gulácsi at Jul 11, 2013 at 5:34 pm
    -1

    --
    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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Svip at Jul 11, 2013 at 8:08 pm

    On 11 July 2013 19:22, Nick Craig-Wood wrote:

    Those two errors say `f()` isn't a value, and return doesn't need a
    value. Since f() isn't a value why can't we put it after return which
    doesn't need one?

    In my opinion the above makes Go slightly irregular, whereas C is
    perfectly regular in this respect.
    Not really, because if someone reads `return f()`, they assume that
    f() will return something we are further returning outside of this
    function. The issue may be easy to catch in your example, because the
    code is so small, but in large functions (or if f() is in an entirely
    different file or package) this would be potentially confusing and
    most importantly, not very logically.

    A return statement in a function that returns nothing is merely saying
    'exit'. Why are you exiting while calling a function?

    --
    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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jesse McNelis at Jul 11, 2013 at 11:31 pm

    On 12/07/2013 3:23 AM, "Nick Craig-Wood" wrote:
    There will be no silent bugs.
    I can certain think of places where the types match up but the intention
    might not.
    It's also horrible to read, it looks like a mistake and anyone reading it
    is going to have to spend time figuring out if it is actually a mistake.
    Your wish to avoid fixing a few lines of code endlessly dooms all future
    readers to waste time.

    --
    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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nick Craig-Wood at Jul 11, 2013 at 11:47 pm

    On 12/07/13 00:31, Jesse McNelis wrote:
    On 12/07/2013 3:23 AM, "Nick Craig-Wood" wrote:
    There will be no silent bugs.
    I can certain think of places where the types match up but the intention
    might not.
    It's also horrible to read, it looks like a mistake and anyone reading
    it is going to have to spend time figuring out if it is actually a mistake.
    Your wish to avoid fixing a few lines of code endlessly dooms all future
    readers to waste time.
    Actually my wish is to make the language perfectly regular not to save a
    few lines of code.

    I wouldn't want to doom anyone to wasting time though ;-)

    --
    Nick Craig-Wood <[email protected]> -- http://www.craig-wood.com/nick

    --
    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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Kevin Gillette at Jul 11, 2013 at 5:45 pm

    On Thursday, July 11, 2013 10:46:25 AM UTC-6, Jan Mercl wrote:

    The return statement syntax, where its owning function has a return value,
    is 'return <expression>'.
    You mean `return <ExpressionList>`. The semantics of returning call
    expressions goes beyond what the grammar can express, and is most simply
    described in terms of compatibility of returned types: if the call's
    returned types are compatible with the callee's returned types, then the
    call can be used as the bare expression in a return statement.

    The question would then be is void compatible with void? I'm tempted to
    take the same approach as NaN, which is not equal to anything else
    including NaN.

    Sensibly, `return someVoidFunc()`, were it valid, would only ever save
    _exactly_ one line of code, while greatly decreasing readability -- `return
    f()` suggests that some value is being returned, and it shouldn't take a
    compilation attempt to quickly determine if that line was a refactoring bug
    or was simply attempting to save a single line of code. I appreciate that
    we're forced to aid readability in these cases. Besides which, Go forces
    you to wrap all control structures in braces, so the benefit of
    "one-liners" is negligible.

    --
    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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Brendan Tracey at Jul 11, 2013 at 5:52 pm
    Sorry, what is this code supposed to do? Can't you just do

    http://play.golang.org/p/pBgAh9rSDj

    or

    http://play.golang.org/p/jXv9g1m52V

    to achieve the same effect?
    On Thursday, July 11, 2013 10:45:05 AM UTC-7, Kevin Gillette wrote:
    On Thursday, July 11, 2013 10:46:25 AM UTC-6, Jan Mercl wrote:

    The return statement syntax, where its owning function has a return
    value, is 'return <expression>'.
    You mean `return <ExpressionList>`. The semantics of returning call
    expressions goes beyond what the grammar can express, and is most simply
    described in terms of compatibility of returned types: if the call's
    returned types are compatible with the callee's returned types, then the
    call can be used as the bare expression in a return statement.

    The question would then be is void compatible with void? I'm tempted to
    take the same approach as NaN, which is not equal to anything else
    including NaN.

    Sensibly, `return someVoidFunc()`, were it valid, would only ever save
    _exactly_ one line of code, while greatly decreasing readability -- `return
    f()` suggests that some value is being returned, and it shouldn't take a
    compilation attempt to quickly determine if that line was a refactoring bug
    or was simply attempting to save a single line of code. I appreciate that
    we're forced to aid readability in these cases. Besides which, Go forces
    you to wrap all control structures in braces, so the benefit of
    "one-liners" is negligible.
    --
    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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Jan Mercl at Jul 11, 2013 at 6:39 pm

    On Thu, Jul 11, 2013 at 7:45 PM, Kevin Gillette wrote:
    On Thursday, July 11, 2013 10:46:25 AM UTC-6, Jan Mercl wrote:

    The return statement syntax, where its owning function has a return value,
    is 'return <expression>'.

    You mean `return <ExpressionList>`.
    No, I don't mean <ExpressionList> because such function is not a value
    usable in an expressions I talked about.

    -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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.
  • Nigel Tao at Jul 11, 2013 at 11:04 pm

    On Fri, Jul 12, 2013 at 1:12 AM, Nick Craig-Wood wrote:
    ------------------------------------------------------------
    #include <stdio.h>

    void f(void) {
    printf("f\n");
    return;
    }

    void g(void) {
    printf("g\n");
    return f();
    }

    int main(void) {
    g();
    return 0;
    }
    ------------------------------------------------------------

    I suspect it works in C and Python because functions always return
    something though that may be void/None whereas go functions really can
    return nothing.
    Heh, I'm surprised that this does work in C because the example from
    http://en.wikipedia.org/wiki/Unit_type does not:

    --------
    void f(void) {}
    void g(void) {}

    int main(void)
    {
       f(g()); // compile-time error here
       return 0;
    }
    --------

    --
    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 [email protected].
    For more options, visit https://groups.google.com/groups/opt_out.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedJul 11, '13 at 3:12p
activeJul 11, '13 at 11:47p
posts12
users9
websitegolang.org

People

Translate

site design / logo © 2023 Grokbase