7 ms·
Having expicitly optional/nullable types is great in languages which are religious about it, since they remove a lot of useless branching and complexity from th
by petree 6y ago
Having expicitly optional/nullable types is great in languages which are religious about it, since they remove a lot of useless branching and complexity from the code. If it's just tacked on, then it just tends to look ugly, without solving any problems.
- bqmjjx0kac 6y agoSyntactic sugar makes a big difference as well, e.g. Rust's `?` operator.
- donio 6y agoRelative lack of syntactic sugar is one of Go's best features though.
- jzoch 6y agoI dont think thats true at all. Even the sugar they have is strange: see `go` and `make`. Go has plenty of good features and "lack of ergonomic faculties for common programming idioms in Go" is not one of them.
- morelisp 6y ago`new` is basically syntactic sugar (and I personally rarely use it), but `make` is the only way to dynamically allocate or to pre-allocate slices and maps.
- wagslane 6y agoSimplicity in Go is one of it's most loved features. For the most part, there are fewer ways to do the same thing and I love that.
- gher-shyu3i 6y agoIt's actually only superficial simplicity. There have been good comments on HN about this issue. Just because the language is "simple", it doesn't hide the complexity of reality, and written code ends up being harder and more verbose and more difficult to manage compared to powerful languages.
- philosopher1234 6y agoWith all due respect those comments you’re referencing generally don’t know what they’re talking about. There is a lot hatred on this website for Go, which appears to have more to do with “I don’t understand why it’s designed this way, and I think all good languages should look like lisp/Haskell/rust” than “this design is net negative for developers”. Practical simplicity is all about hiding complexity. Unless you’re building a race car, you don’t need to know the differences between file handling in Linux Mac and windows. It just never comes up. And when it does, it’s possible to peak under the hood. A lot of the criticism of go mistakes “difficult to write” or “not trendy” for “bad design”, and again I assert this is because the critics don’t actually understand what Go is designed for, period.
- stouset 6y agoWith all due respect, I do understand why go was designed the way it was, and I vehemently disagree with those decisions. I used go for years, and with every passing day I grew more and more disenfranchised with the language. GP is right. Eschewing abstractions in a programming language forces users of that language to deal with it themselves on a recurring basis. Millions of lines of if res, err := fn(...); err != nil { return nil, fmt.Errorf("...") } don't help anyone, and only detract from readability which is bar none the most important part of a code base. Sadly, this is one of many symptoms in the language where problems that could have been solved in the language have instead been pushed down to its users to deal with over and over and over.
- philosopher1234 6y agoYou claim to understand the decisions, so I’ll push you on that. Why is go error handling designed the way it is? What are the intended benefits? What are the actual benefits? A follow up, on your abstraction point: why does go eschew abstraction? Intended upside? Actual upside? It’s very clear people in these threads can perceive downsides of some of Go’s decisions, but what about upsides? And further, can you recognize how Go copes with the downsides it’s choices produce?
- tsimionescu 6y agoI don't think I know of a single thing where there are fewer ways of doing something in Go than there are in Java. There are multiple ways to declare a variable, to pass a value to a function, to declare a constant, to create something similar to an enum, to return errors, to check for errors, to handle closing, to synchronize parallel threads of execution, to initialize a struct, to create a list of items. I can probably go on. What are some examples where Go is simpler than Java, other than its current lack of generics which has always been a known-limitation?
- sagichmal 6y agoThere is one way to iterate over things, for any kind of elementwise processing: a `for` loop. There is one way to format your code ;)
- tsimionescu 6y agoThere are still two ways: the C-style for loop and its variants (for initializer; condition; increment) and the range for loop with its variants (iterate by key, by value, or both). There's also the option of writing a recrusive function. Still less than Java's five (do-while, while, C-style for, range for, recursion), to be fair.
- searchableguy 6y agoFor any complex codebase, people will build their own sugar and that may differ in implementation so it depends whether that is a good idea. Subtle differences in similar looking code can trip people and increase complexity. Fortunately, go has a good standard library to compensate for some of it.
- stouset 6y agoWhich is simpler? if (ptr == null) { return nil, fmt.Errorf("bad"); } val := *ptr or let value = ptr? If `?` is unacceptable complexity, how on earth do you deal with functions—or, even worse—control flow keywords?
- sagichmal 6y ago`?` makes code substantially less coherent, not more.
- stouset 6y agoI would love to see some rationale behind this opinion.
- sagichmal 6y agoI think the core of it is the belief that error handling is no less important than "happy path" code. In some domains, this isn't true. In mine, distributed systems, it is. So I don't want to relegate errors to some ghetto, I want them to be front and center, equal to everything else. Another small part is probably how you think about the error values themselves. I almost never want to pass an error to my caller exactly as I receive it, I almost always want to do something to it first, most often decorating it with relevant context and metadata where I receive it. Sometimes, obscuring it, if I don't want to leak implementation details. But ultimately it's about explicitness, obviousness. `?` is easy to miss, and permits method chaining, the outcome of which is incredibly easy to mispredict. And in imperative code, which is the supermajority of all code, `?` gives no meaningful increase in speed-of-reading -- which is a bogus metric, anyway. So for me, strongly net negative.
- stouset 5y ago> I want them to be front and center, equal to everything else. That’s fine, and that’s why the function itself will have a return type of `Result<T, E>` for some meaningful return type T and error type E. Even better, if there’s an error, there is no non-error return value. You can’t accidentally use the zero-valued return half of a tuple (as you can in golang) because it simply isn’t there. Is the important part of error handling having some copy-pasted stanza repeated everywhere? Or is it enforcing that errors are always handled and semantically-undefined return values are never accidentally passed along in the event of an error? > But ultimately it's about explicitness, obviousness. `?` is easy to miss, and permits method chaining, the outcome of which is incredibly easy to mispredict. No, it simply is not. `?` early-aborts the function and returns the result straight away if it’s an error, and unwraps the interior value if not. There is no plausible way for someone to mispredict this behavior, and if there was, it would be no different from golang, since the two constructs are semantically virtually identical. One is simply shorter than the other. `?` is no less explicit than three lines of copy-pasted code and both its existence and behavior are forced due to the function’s return type. > And in imperative code, which is the supermajority of all code, `?` gives no meaningful increase in speed-of-reading -- which is a bogus metric, anyway. Ease of understandability is almost hands-down the most important metric given the ratio of frequency to code being read versus written. And to be completely blunt, it is flatly ridiculous that wrapping every line in nearly-identical error handling code somehow doesn’t impair comprehension. The argument is the same for abstractions like `map`, `select`, `reduce` et al. Intent and behavior of code can be understood at a glance when you remove the minutia of looping, bounds-checking, and indexing and focus on just the operation. And as an added bonus, you remove surface area for potential bugs like off-by-one or fencepost errors. Having nearly identical error-handling everywhere both in theory and in practice obscures the places where something is different. It is hard to notice small differences in largely-identical blocks of visual information—hence the existence of “spot the difference" games—but it is trivial to spot when those differences are large. I genuinely struggle to comprehend how people can have ideas like this when they fly in the face of what little hard evidence we do have about syntactic differences in programming.