Returning a void function

4,324 views
Skip to first unread message

Nick Craig-Wood

unread,
Jul 11, 2013, 11:12:42 AM7/11/13
to golang-nuts
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 <ni...@craig-wood.com> -- http://www.craig-wood.com/nick

David DENG

unread,
Jul 11, 2013, 11:48:43 AM7/11/13
to golan...@googlegroups.com
Even in C/C++, I seldom write in this way.

David

Jan Mercl

unread,
Jul 11, 2013, 12:46:25 PM7/11/13
to Nick Craig-Wood, golang-nuts
On Thu, Jul 11, 2013 at 5:12 PM, Nick Craig-Wood <ni...@craig-wood.com> 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

Nick Craig-Wood

unread,
Jul 11, 2013, 1:22:56 PM7/11/13
to Jan Mercl, golang-nuts
On 11/07/13 17:46, Jan Mercl wrote:
> On Thu, Jul 11, 2013 at 5:12 PM, Nick Craig-Wood <ni...@craig-wood.com> 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.

Tamás Gulácsi

unread,
Jul 11, 2013, 1:34:06 PM7/11/13
to golan...@googlegroups.com
-1

Kevin Gillette

unread,
Jul 11, 2013, 1:45:05 PM7/11/13
to golan...@googlegroups.com, Nick Craig-Wood
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.

Brendan Tracey

unread,
Jul 11, 2013, 1:52:12 PM7/11/13
to golan...@googlegroups.com, Nick Craig-Wood
Sorry, what is this code supposed to do? Can't you just do 


or 


to achieve the same effect?

Jan Mercl

unread,
Jul 11, 2013, 2:38:53 PM7/11/13
to Kevin Gillette, golang-nuts, Nick Craig-Wood
On Thu, Jul 11, 2013 at 7:45 PM, Kevin Gillette
<extempor...@gmail.com> 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

Svip

unread,
Jul 11, 2013, 4:08:46 PM7/11/13
to Nick Craig-Wood, Jan Mercl, golang-nuts
On 11 July 2013 19:22, Nick Craig-Wood <ni...@craig-wood.com> 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?

Nigel Tao

unread,
Jul 11, 2013, 7:04:40 PM7/11/13
to Nick Craig-Wood, golang-nuts
On Fri, Jul 12, 2013 at 1:12 AM, Nick Craig-Wood <ni...@craig-wood.com> 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;
}
--------

Jesse McNelis

unread,
Jul 11, 2013, 7:31:27 PM7/11/13
to Nick Craig-Wood, golang-nuts, Jan Mercl


On 12/07/2013 3:23 AM, "Nick Craig-Wood" <ni...@craig-wood.com> 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.

Nick Craig-Wood

unread,
Jul 11, 2013, 7:47:11 PM7/11/13
to Jesse McNelis, golang-nuts, Jan Mercl
On 12/07/13 00:31, Jesse McNelis wrote:
>
> On 12/07/2013 3:23 AM, "Nick Craig-Wood" <ni...@craig-wood.com
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 ;-)
Reply all
Reply to author
Forward
0 new messages