

The language I wish Go was - dochtman
http://journal.stuffwithstuff.com/2010/10/21/the-language-i-wish-go-was/

======
stcredzero
_tl, dr; This post ended up way longer than I expected. Super science summary:
I wish Go had tuples, unions, constructors, no Nil, exceptions, generics, some
syntax sugar, and ponies that shoot Cheez Whiz out of their noses._

There's always D, if you want more whiz bangs. It's been oft quoted, that good
library design involves leaving someone wanting more. I think one form of good
language design involves this too. Go is supposed to be minimalist. I think
it's a good sign if people keep wishing it were just a little less minimalist.

~~~
CountHackulus
I'll have to agree with the D comment. As someone who actually writes in D
(for fun), I felt that it was more like a checklist for D than a wish list for
Go. Though yes, I will concede that Go + those changes != D.

Unfortunately, the Cheez Whiz ponies aren't implemented yet, but if D ever
hits 3.0 maybe it can be pushed into the spec.

~~~
sausagefeet
I got the impression he wanted something close to Ocaml than to D. D is much
more complicate than what he is proposing.

------
papaf
I mostly program in Clojure now and I have only used Go a little bit. However,
I really like Go.

I have a lot of respect for the people who developed Go. I'm sure in their
many years of designing operating systems and languages that the features
described in these obvious criticisms were considered. That is not to say the
language shouldn't be criticised but, in this case, a little research would
have made the article a more interesting read.

To take two examples. Constructors are easy to write in GO:

[http://sites.google.com/site/gopatterns/object-
oriented/cons...](http://sites.google.com/site/gopatterns/object-
oriented/constructors)

An exception-like mechanism has been proposed:

[http://groups.google.com/group/golang-
nuts/browse_thread/thr...](http://groups.google.com/group/golang-
nuts/browse_thread/thread/1ce5cd050bb973e4/8bc45b58a32aed25)

~~~
uriel
> An exception-like mechanism has been proposed:

Proposed _and implemented_ almost six months ago.

But that doesn't stop people from writing criticisms of the language and
asking for their pet features after a cursory watching of Rob's original (and
very superficial) talk. _sigh_

~~~
vilya
Exception-like is not the same as proper exceptions. From what I've read about
it (there's the caveat: I haven't used it yet), the error handling model in Go
sounds pretty badly broken.

~~~
papaf
_the error handling model in Go sounds pretty badly broken_

Broken in what way and what have you read? I'm genuinely interested.

I don't want to end up doing language advocacy for a language I hardly use,
but you seem to be confusing error handling with exception handling -
something the design of the exception-like mechanism was designed to prevent.
As I understand it, in this approach, errors are things you expect to happen
(but are errors) and exceptions are things you never anticipated.

~~~
vilya
Calling it error handling was actually a deliberate choice: since
defer/panic/recover isn't an exception mechanism, it wouldn't have made sense
to call it one.

What I've read about it so far is the original "Proposal for an exception-like
mechanism" thread on the golang-nuts group [1]; and the "Panic, defer and
recover" article referenced in the Go FAQ [2]. If any of the stuff below is
misinformed, or just plain wrong, I'd love to hear: Go is a language that I
want to like.

So now the things I object to:

With Go's model, as I understand it, you can call panic with an arbitrary
value. To handle that reliably, your deferred block has to check the type and
dispatch to appropriate handler code yourself. That's something you get for
free with exceptions, where you can generally provide separate catch blocks
for different types of exception.

When you recover from a panic, the execution of your function is over. So if
you have two operations which can panic and you want to be sure both are
attempted, you have to wrap each one in a separate function. It also means the
only way to tell if a function panicked (in case you need to do further
cleanup, say) is by checking the return code - and you'd better hope that
everyone is following sensible conventions for what they return there.

That leads to another point: Go encourages checking return codes to see if a
function failed, whether or not there was a panic. One of the big advances
from exceptions, to my mind, was that you no longer had to mingle control flow
information with application data. Keeping the two separate makes it easier to
write reliable software because it's more self-documenting.

On a more subjective note, I find the syntax really clunky. The examples I've
seen all seem to wrap the handler code in an anonymous function: defer func()
{ ... }() I imagine it would get pretty noisy if you were registering several
handlers that way (much like event handlers in Java were).

I don't necessarily think exceptions are perfect either, just that Go's
alternative seems like a step backward. But I'd actually quite like to be
shown that I'm wrong about this.

[1] [http://groups.google.com/group/golang-
nuts/browse_thread/thr...](http://groups.google.com/group/golang-
nuts/browse_thread/thread/1ce5cd050bb973e4/8bc45b58a32aed25?q=defer+panic&lnk=ol&);
[2] <http://blog.golang.org/2010/08/defer-panic-and-recover.html>

------
jimbokun
"Now when you need to read from a file, you just do:

    
    
        ReadFile(filename, func(file) {
            fmt.println(file.Read())
        });
    

Now you’re safely guaranteed to close the file when the operation is done.
This works because Go has lexical closures, a really nice feature. But the
syntax for this is ungainly. Ruby addresses this with block arguments.
Translated to Go, they could look something like:

    
    
        ReadFile(filename) do(file) {
            fmt.println(file.Read())
        }

"

He does realize, that all he did was replace "func" with "do", and moved some
parentheses around, right?

Are there other examples where the difference is more dramatic than this?

~~~
barrkel
Of course he does. And yes, this small syntactic difference does have effects
in the real world; rename 'func' to 'delegate', and with the addition of a
semicolon (at the end of the println() call) this is valid C# code today - but
almost noone writes their resource protection using this idiom because it's
ugly.

~~~
masklinn
> this is valid C# code today - but almost noone writes their resource
> protection using this idiom because it's ugly.

Incorrect (and you don't need delegate, C# has lambdas now). It's because C#
doesn't use that for its stdlib and instead has a (redundant) special form and
defined protocols.

~~~
barrkel
It is correct to say that replacing the func with delegate and adding the
semicolon makes it valid C# syntax. The correctness of that statement is
completely independent of C# lambdas, which are neither a complete subset nor
a complete superset of C# anonymous delegates.

And it is ugly. It's ugly because the argument list visually expands across
more than one line, including whole statements. The "redundant" forms of
"using" and "lock" are both more limited than the closure-passing approach,
but their limitations haven't been pressing enough to overcome much of tthe
ugliness of the closure-as-parameter approach for this specific case of
passing a statement block.

------
Symmetry
Totally agree about Unions, and I think that one of the reasons that nil is
there might be because there aren't any yet.

I'm not sure I agree about overloading, though. Maybe something like Haskell's
infix notation (1 `add` 2) would be good enough.

------
vinutheraj
The discussion over at golang-nuts, the official mailing list -
[http://groups.google.com/group/golang-
nuts/browse_thread/thr...](http://groups.google.com/group/golang-
nuts/browse_thread/thread/4ac917c9cf43e529)

------
seles
"Once you have constructors and you can statically ensure that every variable
has a chance at initialization, you can start to escape one of the most
unfortunate language misfeatures in wide use today: null"

Question, can anyone think of a case where the lack of pointers being able to
point to null will make it more difficult to implement something? That is will
you lose expressivity if this becomes impossible?

~~~
masklinn
The only case is when you want to express data is missing (not that a variable
is unitialized, but that there's nothing there, think ternary boolean) and
that is very neatly taken care of by option types (ML's `option`, Haskell's
`Maybe`) which you can easily replicate via union types (create a type Nothing
with a single value `nothing` and replace what was formerly a nullable type
`T` by the union type `Nothing | T`; depending on whether you want these to be
easy to use or not, you may or may not want to add the ability to lift
computations into the option type)

~~~
silentbicycle
Right. The language makes you check for nulls at the few places where the
result can go null, and all other tedious null-checking goes away _forever_.

All the advanced type system jiggery-pokery aside -- that's probably the best
"normal programmer" example of why ML & Haskell do static typing better. The
ALGOL family of languages should have done that years (decades!) ago.

------
SeanDav
He mentions BitC. Any comments about this language as I have never heard about
it before?

~~~
Avshalom
I don't have a lot to say about it personally but it came up fairly often on
LtU <http://lambda-the-ultimate.org/search/node/bitc>

------
shin_lao
Sorry to nitpick, but one should say

"The language I wish Go _were_ "

~~~
sid0
Please read
[http://itre.cis.upenn.edu/~myl/languagelog/archives/005515.h...](http://itre.cis.upenn.edu/~myl/languagelog/archives/005515.html).

~~~
jmulho
The link says:

'As a result, appeals to "preserving distinctions" that are "important for
communication" and to "avoiding ambiguity" are baseless and indefensible in
this case.'

"no matter which form you use, people will understand what you are trying to
say."

That is simply not true. Case in point: when I saw the title "The language I
wish go was" I expected to find an article about google cancelling the go
language.

~~~
Abscissa
That would have been written "The langauge I wish Go had been"

------
nickik
In general I think he is right but he has to start use D not Go.

------
gmaster1440
Give ooc-lang.org a try ;)

------
sid0
You know what I wish Go had? Compiler-enforced immutable state. It is
_inexcusable_ that a language designed for concurrent programming in 2010
doesn't support immutability [1].

[1] [http://groups.google.com/group/golang-
nuts/browse_thread/thr...](http://groups.google.com/group/golang-
nuts/browse_thread/thread/0678c6dcdefb21ca)

~~~
jashkenas
Rob Pike answers this question directly in the last couple minutes of his Go
talk at the Emerging Languages Camp, earlier this summer. I think it's pretty
illuminating as to the rationale behind why Go does it the way it does.

<http://confreaks.net/videos/115-elcamp2010-go>

Check out the video, but here's a rough transcription of part of it:

"This is a systems language, which means you should have the choice to do
efficient things, if you know what you're doing. You shouldn't be told "you
can't do that because you might get it wrong." Let me explain. The model for
sharing and locking all that stuff is like having a big piece of paper and we
all gather the paper and we make notes on it about who owns what, when -- and
we scribble and erase and rewrite and work on it. _This_ model is: you don't
have one piece of paper, you have lots of pieces of paper. And you write a
message on a piece of paper, and you give him that piece, and he goes away,
and you don't have it anymore. He'll bring it back to you if it's relevant to
you; he won't if it's not. And because the individual pieces are broken up,
there's no concern or worry about who owns what at any one time -- it's
whoever's got ahold of it at the moment. And once you understand that, it just
doesn't come up as an issue, that for efficiency reasons, I want to pass a
pointer on a channel, because once I've passed it I forget it. The only person
who has it is the person whose business it is to deal with it now. If you're
worried about it and you really care: don't pass a pointer, pass a value. Make
it a channel of struct, rather than a channel of pointer to struct. It will be
a copy, and there's no way you can share it. But that's _your_ decision, not
the language's."

~~~
barrkel
The rationale "You shouldn't be told 'you can't do that because you might get
it wrong.'" applied to language design is always suspect. Almost all features
added to languages above raw assembler are there to prevent you from doing
things that you might get wrong. The flipside of that is having particular
syntax that lets you opt in to doing the potentially dangerous thing.

Safe by default, dangerous by responsible choice.

~~~
InclinedPlane
More to the point, a languaage that doesn't provide the tools to manage when,
where, and what "dangerous choices" you make is much less worthwhile than a
language that does.

C#, for example, doesn't let you modify objects passed in as parameters,
unless you highlight that behavior on the method signature and the call itself
with the appropriate keywords. There are many other examples in many other
languages. "Do what you want, use convention to keep safe" is a recipe for
trouble that has caused innumerable very serious defects in software (buffer
overflows, security vulnerabilities, etc.) "Do what you want, and you have all
these tools to keep track of it" is a much better choice, even if in the end
the code does the same exact thing. Banking on humans not making mistakes is
not robust.

~~~
stcredzero
_Banking on humans not making mistakes is not robust._

This should be expressed as a bumper sticker. How about: Human Error: Bet on
it!

