Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

That feels about right, but missing the most important measure, IMO, which is it takes 10-100x less time to read and understand a new codebase.


Disagree hard!

    a = append(a[:i], a[i+1:]...)
That’s the recommended implementation of erase(). After this, is the original object referred to by ‘a’ modified? How can you tell?

Let’s pop from a stack:

    x, a = a[len(a)-1], a[:len(a)-1]

Did you read that 100x faster than ‘a.pop()’?

Now this:

    a = append(a[:i], append(make([]T, j), a[i:]...)...)
This is an operation called “expand.” What does it do? It is an honest question, I have no idea.

These are completely idiomatic examples taken from the Go wiki. They are not readable.


The number of times I had to do this in practice over tens of thousands of lines of production Go code is about 3.


That surprises me. I have to manipulate slices all the time! Popping an item from a slice, reversing one, or clearing one without allocation in a hotspot is super common for me.

I've used Go professionally for 6 years and love it, so the patterns are ingrained in my head and don't bother me. But it seems pretty clear that it's much more arcane than alternatives.


Slice operations are deliberately verbose in this way so as not to hide the cost of allocation that goes along with them. They are not common in code, but they do make good strawmen when you want to counter general points with specific ones.


I don't think myself or any other Go devs I have worked with have once thought about allocation cost when using slice operations. This may be something super common for C/C++ devs but the big adopters of Go are Python and Java converts where we just don't pay attention to this stuff and after a decade or more of writing this kind of code were not going to suddenly start thinking in terms of memory allocation cost.

I think this is one of those mistakes in the language that exist because early-on Go could have been a true systems language but it's been adopted by a large number of devs more as an infra and high-level automation language where correctness is more important than performance.


Slice operations are verbose because abstracting over them requires generics. Generic operations which don't allocate, like pop, are just as verbose as generic operations which do, while operations on slices of a specific type can be made non-verbose because it is possible to abstract over those. There is no principle of "deliberate verbosity so as not to hide the cost of allocation".


Aligned incentives? Making a “simple” operation as hard to write as it will be on the machine.


While not objectively a bad thing, that's at the crux of the problem many have with Go: it sets the bar very, very low for getting in your way instead of trusting you to be even slightly competent. Knowing basic data structures is engineering 101,and any engineer who'd (eg) blindly use std::find on a vector or "in" on a list in performance-critical code without understanding it isn't someone who should be committing code without review in any case. Inefficient data structure operations are also precisely the kind of thing that's easy to catch in code review.

Don't get me wrong, this isn't a general-purpose argument and I'm not one of those people who thinks that the language should completely get out of your way: eg I'm not a Rust user but its unergonomic handling of memory safety seems far preferable to the ease with which you can shoot yourself in the foot with C++. I definitely see the appeal of Go's handholding in a directional sense. But the degree to which it takes it makes it feel like an unserious or educational language, unnecessarily difficult to get actual work done in, like Javascript but for the exact opposite reasons (and to be clear, Javascript is INFINITELY worse).

This makes it sound like Im more negative on Go than I am, but I think it's the first time I've been able to articulate what deflated my initial interest in it and kept me away from it. Perhaps if feel differently if I had still been a student and new to programming when Golang was released.


> While not objectively a bad thing, that's at the crux of the problem many have with Go: it sets the bar very, very low for getting in your way instead of trusting you to be even slightly competent.

And there's nothing wrong with that, that's exactly Go's target audience.


I spent years as a consultant reading codebases in different languages. I can tell you that Golang win hands down for clarity of code and structure of projects (and perhaps second after Rust in terms of security. If only it had options<>...)

So yeah, it's actually quite fast to dig in a Golang codebase. You notice that as a normal user when you find it faster to read the standard library vs reading the doc, or when you read an implementation instead of reading a spec/algorithm to learn about it.

My guess is that gofmt is a huge factor in this, but also the fact that there's not a huge amount of built ins, anf that the standard library is pretty complete.


Go is the only language where I look at the standard library source instead of google whenever I run into an ambiguity in the docs. I think there are three reasons for this.

First, the docs link to the actual line in source, so it’s just a click away and available in the exact context I need it.

Second, I know I’ll be able to understand it: there are usually very few dependencies, so I can usually get all the context I need from a single file; the source formatting is familiar; code style, like variable names, are familiar because of the cultural influence of the Tour of Go; and there is usually no magic anywhere—I know that things are exactly what they appear to be, like when I see a variable declaration, it is not secretly calling a complex function (this is vital to human knowledge and is aligned with Objectivist epistemology’s “law if identity”).

Third, every time I look at the standard library source, I become a better programmer. I’ve lost track of the number of times I’ve thought to myself “oh, that’s a clean way to organize this kind of code!” I often end up immediately using what I learn from the stand library source.


I agree, and if others disagree they should comment and explain why instead of downvoting you.

One of Go's major selling points (for me anyway) was a solid standard library written mostly in conventional Go style. It's a great example of how Go code should be written, and a wonderful learning tool for the language.

It also makes participating in the community easier because that's one less thing you have to learn in order to contribute.


> My guess is that gofmt is a huge factor in this

It really is. My code looks like your code and the next person's code. Go is opinionated and strict and that makes reading other people's code so much easier


Experts' code should be clearer and more concise than novices' code. If that's not true, there's no payoff for getting more proficient with the language, and it's not doing enough to help you.


golang is not primarily designed for experts

"The key point here is our programmers are Googlers, they’re not researchers. They’re typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They’re not capable of understanding a brilliant language but we want to use them to build good software. So, the language that we give them has to be easy for them to understand and easy to adopt." – Rob Pike


Ironic in a company that prouds itself of PhD hiring games.


This is about readability. There are many other attributes of code (idiomatic? design? efficiency?) that differentiate. But I should be able to grok anyone's code within reason.


I wish gofmt would let you set a desired line length and break it for you.. prettier has me spoiled in that regard


If a tool is going to enforce line length limits, I'd rather have it spit a warning/error than silently try to guess a good place to break the line automatically. Otherwise, an editor tool that soft-wraps long lines at the (often poorly) guessed location without touching the code would be better.


But that’s the thing about prettier - it wraps exceptionally well because it actually parses the AST. I never think about how I space my JavaScript anymore because it always does it correctly.. it’s one less thing to get in my way when I code


The number of options that prettier exposes (despite boasting about being "opinionated", i.e. disregarding the user's opinions) suggests that there are people with different aesthetics or accessibility needs who would not consider one style to be always correct.

IMHO we're about 10 years overdue for committing a canonical representation of that AST to version control instead of treating a particular serialized visualization of it as the single source of truth (and spending countless hours debating which format is "good enough" for everyone in every situation).


You can always set your defaults for your editor.


Packages extensively using reflect + interfaces together can be a bit of a pain to work through. :/


Absolutely. But those are clear code smells. Any org with competent code review would flag them and kill them before they proliferated.


Would you consider k8s to be developed by a competent org? They have 2324 func declarations that take or return an interface{} on master right now.


Kubernetes, like Docker, is notoriously bad Go. The authors essentially transliterated Java.


This. It was really hard to enforce supplementary style across my team to match common conservatism in popular codebases (e.g. only return a single value or a value and bool/error. Don’t expose channels in APIs) when K8s so blatantly fails them.


Have you seen the internals of the Go http library? :)


Have you seen the internals of the rand library? HTTP uses interfaces cleverly to detect optional interfaces. Today I found out that rand.Rand does a type check on every core method to see if it’s source is the hidden type for global methods.


Exactly.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: