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.
For example, he completely missed defer.
Unfortunately, the Cheez Whiz ponies aren't implemented yet, but if D ever hits 3.0 maybe it can be pushed into the spec.
I'd wait first for the any of the existing D2 compiler(s) to at least implement the features that are in D2 'spec', as it currently stands there are no implementations of D2, and that is without going into all the bugs in the most used compilers.
Every language is designed according to that rule. No language designer thinks, "Let me just slap some extra unneeded stuff in there." They just differ on what they consider necessary.
In Go's case, I think many of the things they've omitted from the language are actually useful features and they've just pushed the complexity onto the users. For example, no exceptions just ends up meaning "if err != nil { return nil; }" everywhere.
False. Ruby and Perl were both designed (at least for a time) by adding stuff people were asking for or talking about. Not all language designers set a high priority on the thought, "Can we do without it?"
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...
An exception-like mechanism has been proposed:
http://groups.google.com/group/golang-nuts/browse_thread/thr...
Maybe I didn't clarify it enough, but I tried to explain my problem with initialization functions in the "Future-proofing" section: "If you later need more complex initialization, you’ll have to replace every new(Foo) call with NewFoo()."
An exception-like mechanism has been proposed:
Yes, and implemented and put in the language and referenced in the post. I'm not crazy about panic and defer for reasons spelled out a bit here: http://www.reddit.com/r/programming/comments/du9zu/the_langu...
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
There's more discussion, by me and others, in this past entry: http://news.ycombinator.com/item?id=1576401
A better error handling mechanism may have been a restartable condition system.
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?
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.
I'm not sure I agree about overloading, though. Maybe something like Haskell's infix notation (1 `add` 2) would be good enough.
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?
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.
A better improvement would be to handle null references better - Rails' whiny_nil support is great for example.
These nulls are a different issue than the initialization-originated nulls (that is in fact an other issue with null: they can mean both "I have nothing to put there" and "I forgot to put something there").
> A better improvement would be to handle null references better
No.
> Rails' whiny_nil support is great for example.
whiny_nil exists because you can't do much more in a dynamically typed language, apart from making nil a message sink. Go is not a dynamically typed language, and statically typed language communities have found much better ways to handle most cases where you would use null references decades ago.
"The language I wish Go were"
'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.
[1] http://groups.google.com/group/golang-nuts/browse_thread/thr...
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."
Safe by default, dangerous by responsible choice.
If you're debugging a sharing problem, and relying on convention, you don't even know where to start looking for it in a large codebase.
which means you should have the choice to do efficient things, if you know what you're doing.
That directly clashes with other design choices in Go. For example, taking the address of a variable on the stack implicitly puts it on the heap (at performance cost) to protect you from accidentally using the pointer after that function returns.
If you're worried about it and you really care: don't pass a pointer, pass a value.
...and pay the performance penalty of doing not just a copy, but a deep copy, simply because the language doesn't have const.
I don't have the time to watch the video right now, so maybe I'm reading this out of context, but how does compiler-enforced immutability change this? I'm not asking for everything to be immutable (not even in Haskell is that true) -- I'm just asking for the ability to mark an object as immutable and have the compiler make sure that it isn't modified. I'd prefer that non-local objects be immutable by default, but I'm willing to live with mutable by default.
Really, immutable state gives you the efficiency of pointers coupled with the nice semantics of copy-by-value. It's the best of both worlds -- not having it is denying the programmer "the choice to do efficient things".