It's kind of satisfying to see that the "Go way" wasn't the best way after all and that some of these things are actively being addressed. I hope it makes the community a bit more welcoming as well.
It's kind of satisfying to see that the "Go way" wasn't the best way after all and that some of these things are actively being addressed. I hope it makes the community a bit more welcoming as well.
Sometimes this is just due to defensiveness: someone uses a flaw to say the whole language is terrible and that gets a response from people who have learned to live with the flaw.
Generally, if you back to the original statements you'll find something more nuanced: generic types have a lot of complicated effects on language design and they didn't like their own early proposals, so they started out without them. Yes, error checking can be repetitive, but many of the attempts to fix that in other languages were worse.
In the meantime, the "Go way" is about following common conventions for working within the language's limitations. This isn't a bad thing!
But it's tricky to be welcoming while getting across that the best way to deal with limitations is just to accept them, for now. On the Internet, everyone wants to be Steve Jobs and demand changes.
(Also: Rob Pike, not Erik.)
Except the problem is that "the Go way" changes in a way that breaks your previously-"working within the language's limitations".
An example of this that comes to mind is how the Go 1.5 vendor/ change was done. The community had rallied around several tools that would do vendoring and then would modify GOPATH to include vendor/ and would then symlink the current project into vendor/. All this required was a vendor/src. The Go 1.5 vendor/ implementation was almost identical but they removed the src directory -- which meant that pre-1.5 vendoring was now broken by Go (you can't really have two copies of your vendor tree in a repo and symlinks wouldn't work either).
There are a few other examples of this, but this one sticks out as it was the first feeling I got that the Go development team doesn't really care how the community has decided to work around a language defect. It literally would have just taken them one additional directory to not break every vendor/ project.
(Also, there has been absolutely no discussion with distributions -- as far as I'm aware -- on how packaging Go binaries should be done so we're all forced to come up with our own ideas. The Go modules stuff has considerations -- like builds requiring an internet connection -- that distributions would've had input on, but we didn't get asked about it.)
I think they’re onto something, though as the GP notes, hopefully the situation is improving.
I’d flip your response around and suggest that in several cases, the correct fix is obvious and the core Go team’s insistence on extreme caution and “nuance” is misguided. GOPATH is a great example -- it’s just so obviously wrongheaded that I really don’t understand why it stuck around so long.
Another one that comes to mind, although this is quite old now, is the way early versions of Go would insist that the very last statement of a function was a “return”; you couldn’t do an “if foo { return x } else { return y }”, for example. It took a lot of pushing to persuade the core team to add some basic escape analysis, against insistence that it was some kind of nuanced feature with unpredictable side-effects, rather than a trivial thing that every other real compiler has to do.
My favorite example here is this arrogant dismissal of the idea that a one line expression, rather than a 5 line mutating statement, might be preferred for conditionally setting a value:
if expr {
n = trueVal
} else {
n = falseVal
}
> The if-else form, although longer, is unquestionably clearer. A language needs only one conditional control flow construct. [0]...
n = expr ? trueVal : falseVal
"Unquestionably"If by "one" you mean `if` _and_ `switch` then yes!
&&, ||, switch, select, for, and while all do conditional execution in Go.
So the rule is not "A language needs only one conditional control flow construct." The rule is really, "We didn't think a conditional operator was worth it." That's a fine rule, but it's better to be honest about it than to pretend the language was designed around some pure principle that doesn't actually exist.
However, I wonder how much of this is a difference in substance and how much is about writing style? There is an older, authoritive style that has an implicit "in our opinion, of course" and sounds pretty grating these days.
I remember being taught in school to remove "I think" and qualifiers expressing uncertainty, under the theory that in an opinion piece, that's understood.
Especially these days when hyperbole is common, I prefer writers that have a humble writing style, but also try not to get hung up on stylistic differences.
This isn't an insult to programmers, it is an option that clarity of code is more important then continence. Thus all if and for statements also require {} brackets.
"While the ternary is often clearer, we chose to sacrifice expressiveness and brevity for the sake of preventing abuses, which we found were all too common."
But that is not the claim being made in the FAQ.
> Thus all if and for statements also require {} brackets.
Indeed this rule seems to spring from the same philosophy. It is most certainly not a preference for clarity, though. It is a preference for consistency.
The philosophy is: "We're giving up expressiveness and brevity because in our experience most people can't be trusted to not shoot themselves in the foot."
This choice would be much more palatable if they were honest about it. But instead, they take the road of insisting that the verbose consistency is actually clearer, which it isn't, at least in many people's opinions.
FTR, with "most certainly" you're committing the same fault your accusing the Go team here. You might not think it matters for clarity. I, at least, disagree.
> in our experience most people can't be trusted to not shoot themselves in the foot.
I don't understand the difference between this suggested phrasing and talking about clarity. I'd argue you tend to shoot yourself in the foot if and only if you aren't clear about what you're doing. Clarity and lack of footguns seem directly correlated.
Fair enough. It's too late to edit.
> I don't understand the difference between this suggested phrasing and talking about clarity. I'd argue you tend to shoot yourself in the foot if and only if you aren't clear about what you're doing.
This is partially true but it's not that simple imo.
In my OP, the ternary version is clearer. But if you allow it, then you also open the door to nested ternaries, and foot shooting.
Allowing single line if statements (as, eg, ruby does) also allows for clearer code, at the expense of consistency.
This (or rather allowing conditionals without braces) was what I was referring to. They are a foot-gun, because of the lack of clarity. It's a common source of bugs in C/C++ code that a developer thought they'd add a line of code to a conditional block or loop but didn't, because of a lack of braces. Requiring braces unconditionally make it always unambiguous and obvious what block a given statement belongs to.
Obviously YMMV - this is, as most discussions in programming, a matter of opinion. Which was my point :)
if (condition)
doSomething
to if (condition)
doSomething
doSomething2
So fair enough, you protect against that. You cannot therefore conclude that: if (condition) {
doSomething
}
is clearer or that 1 line if statements aren't clear. First of all, you've purchased your insurance at the cost of brevity. Which is quite a high price, especially when you have to use them constantly to write: if err != nil {
return err
}
and when it forces all of your 1 line conditional expressions to be 4 - 6 lines, per my OP.And there are solutions that allow you to buy your insurance without such a high price. You can invert the position of the if, as ruby does. You could make a rule that when you don't have braces you have to write your statement on the same line. The point is this isn't the only way out. And clarity is not the same as preventing one specific kind of error, which occurs only in a context which could be changed as well.
n = if(expr) trueVal else falseVal
No need to learn a separate ternary operator.The more palatable argument that people who try to cover for ... seems to be that when people nest if expressions, it becomes a mess. I'm glad these people exist.
The real reason is found here: http://dtrace.org/blogs/wesolows/2014/12/29/golang-is-trash/
(or if you prefer, in the compiler's source itself. It doesn't take a compiler expert to realize it's not very clean code. Even violates the go style, and the C one before that was just horrendous)
The TLDR is that Go's compiler is a "fisher-price my first compiler" and really shows that the authors simply barely knew how to get a compiler working in the first place. That they were not ready to go into a rational discussion on programming language and type theory ... is not something anyone should be surprised about.
That they avoid the arguments by dismissing the people making them in such a condescending way is ... well, there's not really anything good to say about that.
(setq n (cond
(expr trueVal)
(t falseVal)))
This particular idea dates back to at least 1965.I was thinking I could write my own if(condition, true_case, false_case) method similar to the way it's done in spreadsheets, but Go also doesn't have macros or inline if/else expressions, so there is simply no way to emulate ternary logic in a performant manner :-(
And the missing ternary will be the least of your problems. Do you enjoy `map` and `filter`? Sorry, the "go way" is to use a for loop every time. Reimplementing map on every type where you need it is considered best practice in Go. Have a problem with that? Expect a snarky comment about your priorities.
This can all be pretty frustrating when you've experienced the joys of more expressive languages.
Go has good concurrency primitives and is fast. That's what it's good at. Those are the reasons to use it. Temper your expectations accordingly.
Whereas your comment is completely devoid of snark.
Not the official docs of a programming language. In one of those, a bit of snark is really quite normal and of no real impact.
Most everything I've seen from the Go camp, including the new re-discovery of various wheels with the Go 2.0 proposals, felt like the parent describes to me.
Never got the same from Rust, otoh.
Or try opening new thread on Swift forum on issues where decisions have been take. They will quickly put you in place and close the thread.
I have yet to see a successful language where whiners are embraced with great enthusiasm.
I don't speak about Rust enthusiasts or even the Rust community at large, there are people like that in all languages (though indeed some communities might be better than others, but with large enough numbers of users of a language you get all kinds of people in a similar enough distribution).
I speak of the core team. Go's one has a vibe I don't get from Rust's.
> pretty much every Go-related conversation over at /r/programming seems to have someone arguing that it's literally impossible to build software in a language that lacks generics
Literally literally? Isn't your reply a "bad way to characterize the overall conversation" as well?
Yes; I've challenged this as hyperbole and people double down.
> Isn't your reply a "bad way to characterize the overall conversation" as well?
I don't think so. My reply characterizes the overall conversation as a difference of opinion about whether or not Go's design choices are matters of tradeoffs, and I believe this to be accurate. I chose my example because it was exceptionally stark, but the point is that if such stark comments are made so frequently, surely there is a long tail of less-stark comments. Anyway, I don't want to belabor the point because we have no data and all we can do is conjecture and stir up bad feelings and likely a flame war, so let's not do that.
Generics is a major tell, too, since the Go team's position on generics was always "generics are interesting but we don't know how to make them work well with Go's existing type system". See for example, this blog post from 2009: https://research.swtch.com/generic which references the FAQ answer to the generics problem here: https://golang.org/doc/faq#generics: "Generics are convenient but they come at a cost in complexity in the type system and run-time. We haven't yet found a design that gives value proportionate to the complexity, although we continue to think about it."
so I can see why people who have repeatedly answered the same question for years, only to have their answer misrepresented for years, to be annoyed when people who haven't read any prior discussion bring up a point that has been already talked about ad nauseam.
It was a comment on my personal experiences of interacting with the Go community, not the language and its limitations. My hope wasn't that Go implements my every pet peeve, my hope is that the community has gained some humility since I last dipped my toes in it.
Pike seems especially aggressive when interacting with people he disagrees with and this was for me indicative of the culture. It's been a few years though, so maybe by now I'm wrong!
Here's Pike on the topic of syntax highlighting:
https://groups.google.com/d/msg/golang-nuts/hJHCAaiL0so/E2mQ...
https://groups.google.com/forum/#!msg/golang-nuts/hJHCAaiL0s...
That was the day I dropped the mailing list.
I disagree with Rob though, syntax highlighting is not juvenile, it's cargo cult programming.
That clearly implies anyone who uses syntax highlighting is juvenile. I'd say calling someone juvenile is meant to be denigrating.
FWIW, as much as I agree with Rob Pike on most things, I totally agree that he's abrasive and his way of phrasing things is often unhelpful (even though I think people also tend to read contempt into his brevity that isn't there). If it helps, I think he has realized that in the meantime and is largely staying out of public discussions for that reason.
edit: addendum: but also, in every thread about Go, there are some Haskell people showing up to talk about how the Go team is too stupid to understand the Haskell type system. This happens regardless of what the opening topic is, which in this case, is dependency management. No matter what the topic is, if it's a thread about Go, you will find Haskell programmers there, condescendingly talking about how Haskell's type system is so much better than Go's type system. It is very tiring.
There were 22 comments, and the one from the Go developer was (and I quote):
"Tempted to stop reading after the first word in the article. (The language isn't called Golang)"
I don't think "factually incorrect" is warranted. It's factually correct that the language is called Go. And while "golang" is a useful alternative for searchability and where "go" is taken, it is still a valid criticism to request using "Go" in natural language and prose. As for "official disambiguation", I'd say the most official thing said on the topic is this FAQ entry, which is quite clear on the matter: https://tip.golang.org/doc/faq#go_or_golang
(not saying Brad's comment isn't abrasive or rude. But it's not "factually incorrect")
The language maintainers regularly and consistently use "golang" as a disambiguation:
* golang.org
* github.com/golang
* Twitter @golang and #golang
* golang-nuts
In this context, it seems pretty "official" and the rebuke "factually incorrect" or at least the rebuke applies equally to the maintainers.
That said, it was a single wayward comment and it is (in my experience) out of character. I want to acknowledge that it was rude and validate the person who was wrongly rebuked; I explicitly don't want to pick on anyone nor tempt the Internet to pile on.
"Sydney Golang Meetup - Rob Pike - Go 2 Draft Specifications"
FWIW, go-nuts was already taken.
Frankly, it's just tiring; especially as a lot of the same points and misconceptions are repeated. Some points are valid, but it's repetitive at best. It would be like discussing Python's significant whitespace with inexperienced Python programmers every week. Sure, it's quirky and arguably not a good idea, but the discussion had been done a few times already.
Turns out that filtering stuff that uses "golang" instead of "Go" is actually a pretty good heuristic for determining if an article is worth reading. Is it perfect? Of course not; it's a heuristic.
Reading your article, this is exactly the sort of "been there, discussed that" kind of example. Your article isn't bad – I think it's mostly on-point – but it's also pretty much a repeat of what many others have said/discussed.
Still, I think my and my parent's point is that: it would have been better if they'd just said nothing.
Yeah, it's an imperfect heuristic. I didn't intend it as a remark about you or your article in particular (I had added a sentence about that in my previous comment, but it must have gotten lost in the editing).
> it would have been better if they'd just said nothing.
Yes, I agree. "If you can't say it nice, then it's probably best to not say anything at all". I thought it would just be helpful to explain some of the frustrations that are (probably) behind the comment.
Given that, they do also 'talk down' in their official documentation. I had to look back in time to understand the memory model for the sync.atomic operations which is documented:
"These functions require great care to be used correctly. Except for special, low-level applications, synchronization is better done with channels or the facilities of the sync package. Share memory by communicating; don't communicate by sharing memory."
The final word on what 'great care' means is that Go doesn't actually have a memory model for this part of the standard library. The discussion thread around it has a different tone than the official documentation. They agree on how they want implementations to operate, but don't feel that it needs to be officially defined or documented. I would have been happy if they at least referenced the discussion thread rather than merely label it 'great care' meaning 'not for you'. The other thing you find is that the performant parts of the standard library often does not follow "Share memory by communicating; don't communicate by sharing memory".
One of the betrayals when working with I/O was finding that standard library routines can return a value AND an error, and that sometimes a non-nil error is not an error (EOF is not the only one of these).
The current way I handle it is that $HOME/.local is my GOPATH, and $HOME/src links to $HOME/.local/src. So you can just have $HOME/src/github.com/bar/foo -- which is less ideal than just $HOME/src/foo, but it's something at least.
But, yes, I rolled my eyes when learning about GOPATH for the first time.
It seems this gets fixed in Go 1.12 though. AIUI you'll be able to set GOMODULES=on, unset GOPATH and just continue working as before.
Next have been oddities with vendoring workflows. Given previous decisions it seemed like the golang team was driving towards vendored solutions but with go mod they seem to have backed off of that position. The workflows with go mod are clunkier & less well documented. Unfortunately I’m (and my teams) are highly invested in vendored libraries.
We’ve also had trouble with it not playing nice with dependencies that have not taken up modules (and some that are unlikely to).
That’s not even to mention my problem with their design or the hamfisted way they have gone about it, which is something I just have to get past.
CLASSPATH, PYTHON_PATH, PERL5LIB, ...
I never really understand the hate here. It seems more like they didn't hate GOPATH specifically and more that they didn't like not having a package manager.
You can put your code anywhere you want and `go build` and `go run` will work just fine.
It's only third party libraries that have to be in GOPATH, which is exactly a library (well, package) search path.
ie if your code itself is split into modules, they won't work (as they are imported by their full path, not relatively), and anything in your vendor dir is also ignored when used outside of a GOPATH entry.
Basically before go 1.11, it was impossible to just do
git clone ... somedir
cd somedir
# build code and run something
You had to instead make sure "somedir" ended up somewhere within a particular deep directory structure. That is what people mean when they say "GOPATH".That's not true. It was always perfectly possible to do that, the code you build just couldn't import any libraries not installed in GOPATH. AIUI that is exactly the same as in other languages.
I guess it is not all that different from Python, with Python you need to add the source path to PYTHONPATH / sys.path (and often do so at runtime in the entrypoint script). With go you need the "src/github.com/dagss" prefix to the path. Or at least, according to conventions. You are right that it is more similar on a technical level than what I thought.
Go solves Googles main problem -> something which new engineers can use to write practical solutions without having to think too much. It's not beautiful or expressive or technically interesting; most "craftsman" devs won't stick with it too long..But that's not the majority of devs google is hiring.
Sit down, bang out code and don't concern yourself too much with craftmanship - it will be re-written in a couple of years. Just worry about performance.