> No type inference. Because obviously it’s 2013 and I want to write types everywhere.
The `:=` does a fair bit for the programmer in cutting back on writing types. For me, the most needed place for type inference would be for writing anonymous closures (like what Rust has). In most other places, I am quite content with writing the types, particularly at the top level.
> Like what’s the point of all the odd rules around := vs =
The former is short-hand for variable declaration with assignment and type deduction, while the latter is just regular assignment. The primary benefit here is type deduction, which partially relieves the lack of type inference.
> and what types you can and can’t assign and pass to functions
Huh?
> And why do you have to declare imports, when the compiler could work them out for you (it’ll even moan if you import something which is not used!)
The compiler absolutely cannot work them out for you. If you have a package `github.com/PeepA/wat` and a package `github.com/PeepB/wat`, how will the Go compiler know which `wat` package to import?
The Go compiler merely moans if an import (or its alias) hasn't been used in the source file that it was imported in. I like this feature, even if it is a mild bother while debugging.
> Hello, world is about 8 lines of code. Camel case! Java rang, wants its boilerplate back.
It's two lines. [1]
> No breakthrough on error handling.
Breakthrough? I'm not sure what you were expecting, but I think the error handling is pretty sane and at least far better than error handling conventions established in C. It could be adjusted if sum types were added to the language, but that has its own trade offs.
If you desperately want exception-style error handling, then you can use panic/defer/recover, but it's frowned upon to overuse it.
> The whole design of GOROOT/GOPATH is completely broken. It’s actually worse than Java’s broken CLASSPATH crap which is some kind of achievement, I guess.
I have the exact opposite opinion. Did you know that you probably shouldn't be setting `GOROOT`? [2] After Go is installed, you just need to set `GOPATH` and add `$GOPATH/bin` to your `PATH`. That's it.
> It’s not even enforced error checking, so bad programmers will still be able to write bad code.
That is true, but Go's compiler forces you to address errors returned by functions that also return another value. You either need to explicitly ignore it or use the variable the error is stored in. (Lest you get an "unused variable" compiler error.) This doesn't cover all cases---like completely ignoring the return value(s) of a function---but don't throw the baby out with the bath water!
> That is true, but Go's compiler forces you to address errors returned by functions that also return another value.
Barely and badly: you can ignore the error and it's by far the simplest course of action. Contrary to Haskell where it is easier to propagate it, or Erlang where it is just as easy to turn the error into a fault if you don't want to handle it.
No, my response indicates that I do not think your post was "tempered, even and acknowledged the shortcomings fairly" (and the one I picked is merely the worst, your hello world is as disingenuous as Java's with all newlines removed — a single line)
But hey, I guess I'll give you credit where credit is due: you do know Go's error handling is only an improvement compared to C's, although you still err in declaring it "far better".
Because I did not expound upon the intricacies of error checking with sum types? Responding to inaccuracies about Go does not imply I need to exhaustively describe all alternatives in order to be even-handed. Namely, I was responding to the OP's claim that the Go compiler did not "enforce" error checking. But it certainly does to some extent. I acknowledged that such enforcement was not exhaustive and that errors could be ignored by the user. I even acknowledged insidious cases where the return values are never captured at all.
> (and the one I picked is merely the worst, your hello world is as disingenuous as Java's with all newlines removed — a single line)
I ran `gofmt` on that code before sharing it, so it conforms to Go's "One True Style". More importantly, my "Hello World" is quite readable, unlike a single line Java "Hello World". This last point in particular addresses the OP's central point: that Go is just as verbose as Java because of the length of "Hello World".
> Because I did not expound upon the intricacies of error checking with sum types?
No, it's got nothing to do with sum types, Erlang does not use sum types yet for all the similarity of Go's error handling to Erlang's, Erlang is vastly superior.
> I acknowledged that such enforcement was not exhaustive and that errors could be ignored by the user.
And that's insufficient, errors can almost always be silently ignored by the user (even in languages with sum types which turn errors into faults, you should be able to silence the fault). The issue in Go is that ignoring errors is the simplest thing you can do. And not only that, not ignoring them is a significant step up in complexity and amount of code.
I'd really appreciate if you stopped quoting me out of context. I never said sum types were the only alternative. The second sentence of my GP was "Responding to inaccuracies about Go does not imply I need to exhaustively describe all alternatives in order to be even-handed." I referenced sum types specifically because it is often what people suggest should have been included in the language.
> The issue in Go is that ignoring errors is the simplest thing you can do. And not only that, not ignoring them is a significant step up in complexity and amount of code.
I agree that error handling requires more code, but I disagree that it increases complexity. Most error handling cases I've ever written are just passing them up to the caller:
if err != nil {
return nil, err
}
That is not added complexity IMO---particularly since it is an extraordinarily strong idiom---so I suppose we are at an impasse.
> It’s not even enforced error checking, so bad programmers will still be able to write bad code.
Bad programmers will always be able to write bad code. You can't structure a programming language around preventing bad code without completely hamstringing the language.
A false dichotomy. You are correct that you can't outright prevent the writing of bad code in any language without crippling it; nonetheless, the design of a language can be contrived such that writing good code is the path of least resistance. It is not a binary choice between "safe but crippled" and "useful/flexible but unsafe". There is an entire continuum of choices to be made between the two extremes. The design of Go's error handling mechanism, while not the worst approach imaginable, unfortunately makes the programmer exert extra effort in order to do the "right thing".
> the design of a language can be contrived such that writing good code is the path of least resistance.
You can only do this for sufficiently motivated and well-informed programmers.
> The design of Go's error handling mechanism, while not the worst approach imaginable, unfortunately makes the programmer exert extra effort in order to do the "right thing".
Most error handling mechanisms I've seen make doing of of the worst things imaginable (silently throwing away the error) the easiest thing to do. I'm not so sure it's any easier or harder to do the right thing in Go, in the particular context of a highly concurrent system.
EDIT: But I haven't investigated Erlang's mechanism yet. I've heard it's quite good.
> The whole design of GOROOT/GOPATH is completely broken.
I too thought this, until I took a couple of minutes to actually understand how it's supposed to be used. It's a very opinionated setup, but it seems well thought out.
The `:=` does a fair bit for the programmer in cutting back on writing types. For me, the most needed place for type inference would be for writing anonymous closures (like what Rust has). In most other places, I am quite content with writing the types, particularly at the top level.
> Like what’s the point of all the odd rules around := vs =
The former is short-hand for variable declaration with assignment and type deduction, while the latter is just regular assignment. The primary benefit here is type deduction, which partially relieves the lack of type inference.
> and what types you can and can’t assign and pass to functions
Huh?
> And why do you have to declare imports, when the compiler could work them out for you (it’ll even moan if you import something which is not used!)
The compiler absolutely cannot work them out for you. If you have a package `github.com/PeepA/wat` and a package `github.com/PeepB/wat`, how will the Go compiler know which `wat` package to import?
The Go compiler merely moans if an import (or its alias) hasn't been used in the source file that it was imported in. I like this feature, even if it is a mild bother while debugging.
> Hello, world is about 8 lines of code. Camel case! Java rang, wants its boilerplate back.
It's two lines. [1]
> No breakthrough on error handling.
Breakthrough? I'm not sure what you were expecting, but I think the error handling is pretty sane and at least far better than error handling conventions established in C. It could be adjusted if sum types were added to the language, but that has its own trade offs.
If you desperately want exception-style error handling, then you can use panic/defer/recover, but it's frowned upon to overuse it.
> The whole design of GOROOT/GOPATH is completely broken. It’s actually worse than Java’s broken CLASSPATH crap which is some kind of achievement, I guess.
I have the exact opposite opinion. Did you know that you probably shouldn't be setting `GOROOT`? [2] After Go is installed, you just need to set `GOPATH` and add `$GOPATH/bin` to your `PATH`. That's it.
> It’s not even enforced error checking, so bad programmers will still be able to write bad code.
That is true, but Go's compiler forces you to address errors returned by functions that also return another value. You either need to explicitly ignore it or use the variable the error is stored in. (Lest you get an "unused variable" compiler error.) This doesn't cover all cases---like completely ignoring the return value(s) of a function---but don't throw the baby out with the bath water!
[1] - http://play.golang.org/p/ihEoJ0yL9I
[2] - http://dave.cheney.net/2013/06/14/you-dont-need-to-set-goroo...