
Comparing Go with Lua - mapleoin
http://steved-imaginaryreal.blogspot.com/2011/09/comparing-go-with-lua.html
======
davidhollander
I'm a big fan of Lua and Go's use of multiple return values, nil, and
simplified error handling, (No exception 'types'). I think the problem with
'typing' Exceptions is that it means you are using it to record and pass
describable\known state similar to return, instead of being reserved for
unknown state. For indicating predictable failure states without using
exceptions, I think multiple return values as used in Go and Lua is a much
better paradigm. To recap Steve's post, opening a non-existent file in Lua:

    
    
        =io.open 'sdfasdf'
        nil	sdfasdf: No such file or directory	2
    

The first value returned is nil, the 2nd value is a string containing an error
message, and the 3rd is an integer error code. This allows you to write most
code using 2 state boolean logic:

    
    
        f=io.open 'sasdasdfsf'
        if f then -- nil is a boolean 0
    

whereas in Python, one often has to reason about 3 states due to the use of
try\except blocks. Even though you are not using typed Exceptions, multiple
return values does not discard any state about the error if it is desired:

    
    
        f, err = io.open 'sasdasd'
        print(err)
    

In Lua (not Go), when you combine multiple return values with an assert()
function of the form assert(boolean, error_message), you effectively get a
mechanism for making exceptions optional:

    
    
        > =assert(io.open 'sdfasdf')
        stdin:1: sdfasdf: No such file or directory
        stack traceback:
        	[C]: in function 'assert'
        	stdin:1: in main chunk
        	[C]: ?
    

Although Go does not appear to include assertions at all, arguing against them
in its FAQ: <http://golang.org/doc/go_faq.html#assertions>

~~~
danssig
IMO going back to return statements for error detection is to throw away years
of advancement. The problem with what you're describing is now every call has
to be tested for errors because only the call-site has a chance to do this.

Contrast this with exceptions: if I don't know what to do with a failure at
this level then I just ignore it. Some caller higher up the chain _will_ know
and can handle it.

Your examples seem overly trivial. In real code it would be very rare for the
level of code that's actually opening files (something far down in the
libraries) to also be handling exceptions.

~~~
rwj
Go actually does provide a mechanism similar to exceptions. The functionality
is provided by the functions panic, defer, and recover. Idiomatic Go does not
like panics (i.e. exceptions) to escape API boundaries, but otherwise you are
just as free to use them as any language providing exceptions.

------
seri
I independently ended up with the same impression with the OP. Go feels just
like a statically typed Lua. Not only does Go inherits Lua in some specific
language features as pointed out by the OP, but it also learns from Lua's
design philosophy: _be minimal_.

When I was going through my journey with Go discovery, I noticed that the Go
authors obsessively tried to keep the syntax size small. There is only one
looping construct. The only polymorphism mechanism is interface, but
interfaces are both very simple and flexible. This is like what Lua does with
tables.

This also means that when a feature introduces complexity into the language,
the Go authors choose to discard it. There are advantages and disadvantages
with exceptions, but I think what ultimately motivated the Go authors to leave
exceptions behind is that it may complicate things. And Go also doesn't have
any kind of compile-time generic, so one can't write functions like append()
and copy() in pure Go.

------
masklinn
> But the big similarity is this: functions can return more than one value.
> This is quite distinct from returning tuples, as Python does and is very
> much more efficient. (Bruce Eckel errs in speaking of tuples in Go) So the
> following style is common: a function returning a value plus an optional
> error:

I have trouble with this assertion: as far as I can tell, _nothing_ would stop
a language (especially a statically typed one) from optimizing a tuple
return/unpack into a cheaper parallel assignment, and still provide a full-
blown tuple type. I might be wrong, but is tuples unpacking not a strict
superset of Go/Lua's restricted multiple return values?

(this is not possible in Python, because Python really unpacks arbitrary
iterables, and Python 3 introduces ruby-style unpacking slices, so you can't
apply such an optimization unless you can infer the exact return type of the
callee)

Multiple return values is not intrinsically more efficient than tuples
unpacking, it's just foisting an optimization onto the language user (by
arbitrarily limiting his options in this case).

Even the following pattern of unpacking into a function arguments can
trivially be handled via tuples unpacking (by making them explicit, which
counts as a positive as far as I'm concerned)

> Go and Lua provide mechanisms for protected calls which are similar in
> spirit. Something bad will happen in a function, and the idea is to prevent
> that badness from bringing down the process.

a.k.a. exception handlers by any other name.

> The strength of the Go approach is that there is an explicit mechanism for
> calling arbitrary code when a function stack frame goes out of scope. With
> Lua (as with most garbage-collected languages) the best you can do is define
> finalizers on objects and wait for the garbage collector to call them
> (eventually.)

Right, because there's no such thing as `BlockClosure#ensure:`, `unwind-
protect`, `using()` or `with:`.

> The difference is that with Go you have to use an underscore if you want to
> ignore the value (it is very strict about unused variables)

The issue with a bare `_` is that it has limited readability. Sometimes, you
want to say "This is that, but I don't care for it". Erlang lets you do that
by `_` being used as a prefix as well as a wildcard (technically I believe it
introduces bindings, but more interestingly it makes the compiler not warn
about unused bindings). It is very useful for bit positional matches of which
half are thrown out.

> Note also the similar for-iterator syntax which naturally flows out of
> multiple return values.

Which you can just as easily get from tuples unpacking, of course.

> Lua's multiple returns came from CLU according to The Evolution of Lua. It
> is interesting how long it can take for new programming language concepts to
> reach the mainstream.

About 17 years[0] is not that much, and that's only if you discount pattern-
matched functional languages[1].

[0]
[http://docs.python.org/reference/simple_stmts.html#assignmen...](http://docs.python.org/reference/simple_stmts.html#assignment-
statements)

[1] <http://en.wikipedia.org/wiki/ML_(programming_language)>

~~~
pcwalton
"I have trouble with this assertion: as far as I can tell, nothing would stop
a language (especially a statically typed one) from optimizing a tuple
return/unpack into a cheaper parallel assignment, and still provide a full-
blown tuple type. I might be wrong, but is tuples unpacking not a strict
superset of Go/Lua's restricted multiple return values?"

Well, it depends on how you implement polymorphic code, but generally yes.
This is why we use tuples instead of multiple return values in Rust. In fact,
if you return a struct by value in LLVM, LLVM will allocate a virtual register
for each element.

------
georgieporgie
It would be nice if the code samples were colored or tagged according to
language, since I know neither Go nor Lua.

