8 ms·
Coming from swift, it's pretty refreshing to see a language that has decided to settle on the language itself pretty early and focused on improving all other as
by bsaul 4y ago
Coming from swift, it's pretty refreshing to see a language that has decided to settle on the language itself pretty early and focused on improving all other aspects of the dev experience.
Last time i ran my go test suite on the CI i thought it had a bug because it was so fast compared to what i'm used to with swift.
I do still have a weird feeling of getting back to the stone age whenever i get a nil pointer panic though. i wish go devs could figure out a way of fixing those last quirks without impacting the rest too much.
- kramerger 4y agoIn this regard Go has been the exact opposite of Rust.
- diarrhea 4y agoIsn’t the Rust DX pretty good still?
- akmittal 4y agoRust has very long compile time compared to Go
- dgunay 4y agoRust could also have shorter compile times, if it gave up on a lot of the optimizations and features it currently does.
- eptcyka 4y agoA massive source of compilation pain is that Rust just generally generates a lot of code - it always prefers specialization over dynamic dispatch unless the source specificies dynamic dispatch. Couple this with a culture of believing dynamic dispatch is always worse and lots of codegen for generics and you get one hell of a task for your linter. I wouldn't call this an optimization, but rather an almost cultural design decision.
- orf 4y agoIt’s more correct to say that it always prefers zero-cost abstractions. Defaulting to dynamic dispatch would go very much against this, even if in some cases it’s not a bad idea.
- vlovich123 4y agoMost of the code is cold. Spending compile time on that probably isn’t worth it. As such it’s not a zero cost abstraction (yes yes - it normally means runtime but still - developer time is important too and that’s where the trade off is). In most cases static dispatch is faster. In many cases dynamic dispatch can be just as fast (speculation by CPU negates the cost) and in some cases it can be faster (better code density). This 0-cost abstraction principle from c++ is actively harmful because there’s almost no such thing. Performance is such a subtle thing that what’s 0-cost in one scenario is a non 0 cost in others. Also spending compile time on the “dark matter” of code that’s rarely executed is probably not the best way to spend the developer time budget. I want CI to generate fully optimal code for production in release builds. For running tests in presubmit, I probably want a little bit less optimization. For local development I want it to be just fast enough that compile times are quick and I can iterate quickly (except for the cases I’m tuning performance in which case I have no choice but to spend max compilation time).
- jeffbee 4y agoI strongly doubt that endless fields of cold/dead code are zero-cost, without profile guidance and link-time optimization.
- morelisp 4y agoOne of my favorite go-to examples for this is "Producing Wrong Data Without Doing Anything Obviously Wrong!" 4.2 where they demonstrate a reproducible >30% performance difference just by "misaligning" stacks with an unused environment variable. That's in the context of unexpected measurement bias, but you won't convince me piles of cold code can't affect memory layout less than that.
- bsaul 4y agoI think the main problem with rust, is that the things they decided to settle on early on (aka the borrow checker) are the ones at the root of all the difficulties. They then tried to tame those issues little by little by improving the language ergonomics. This is pretty different from swift for example. Which had a sane basis very early on, but decided to expand the language by adding features over features, moving the language to a lot of different directions, turning it into an ugly beast ( i still like it though, but i’m not sure for how long).
- mdavidn 4y agoLearning to work with Rust's borrow checker leaves one with the sinking realization that every C program also has a borrow checker: The very fallible programmer.
- microtonal 4y agoNot just C, any language with mutable aliases references/pointers, which is pretty much every modern language. https://blog.polybdenum.com/2023/03/05/fixing-the-next-10-000-aliasing-bugs.html https://blog.polybdenum.com/2023/03/05/fixing-the-next-10-00...
- eru 4y agoWell, Haskell has mutable aliases, references and pointers. But you seldom use them.
- pdimitar 4y agoAt this point in history it should be more or less apparent that "here's a gun you can shoot your foot with, just don't do it lol" is not a viable strategy. It's the strategy of the C devs whose memory safety bugs and buffer overflow mistakes we still find to this day, in a number of popular and very widely used programs. ...Nah. We shouldn't go back (and I am not saying you claim so, I am kind of just developing the thought here). Let's have memory safety and algebraic data types and maybe pluggable GC runtimes (if lifetime management proves too difficult which it has at times; not every task is perfectly suited for Rust's borrow checker) and async, and any other goodies that help us solve real problems, and let's not dream of a simpler life. That "simpler life" has failed. We should acknowledge that and move on and work with the reality in front of us. Rust's lifetime management and async runtime(s) can be maddeningly difficult but after being on all parts of the spectrum -- from bash scripts and JS Wild West projects to Rust -- I confidently claim that the more strictness the better. ...Though I wouldn't refuse Rust having compile times like those of Golang and OCaml, can't deny it.
- Ferret7446 4y agoPretty much the only time I see a nil pointer panic in Go is when a junior dev doesn't initialize a map, which is easy to diagnose and fix (and should probably get a linter). It's a non-issue as far as I'm concerned.
- jeremyjh 4y agoJust don’t write any bugs!
- bsaul 4y agobasically any struct containing pointers can be misinitialized and have nil pointers. it is indeed quite easy to fix most of the time, but it's also a non-issue in a lot of modern PL.
- tjpnz 4y agoIt's an easy mistake to make regardless of experience.
- shp0ngle 4y agoeh, that’s dumb. Most go types have useful default value. Nil slice is a 0 length slice. Default byte.Buffer is an empty buffer. Default of struct is all fields default. That’s all great. Except for map. Which panics. Oops!
- 4y ago
- nobody0 4y agoI wonder why Go doesn't have algebaric data types, it could solve a lot of issues, and make code a lot easier to write.
- pjmlp 4y agoUnfortunately for the same reason it lacks many other modern features introduced by CLU and Standard ML in the mid-70's, language designers don't want to overburn Go developers with PhD level concepts.
- mseepgood 4y agoSounds like a good design guideline, so I wouldn't call it unfortunate.
- Conlectus 4y agoAlgebraic data types (more technically sum types) are very much not “PhD level concepts”, despite the name. They’re just what C developers would call “tagged unions”.
- kaba0 4y agoEspecially when they will eventually have to walk back on their decisions a few years later, see generics..
- foldr 4y agoThey took the time to do it properly with input from experts on type systems (e.g Phil Wadler). The result is probably much better than what we'd have if the Go developers had quickly thrown together an implementation of generics 10-15 years ago. For example, the resulting type system is known to be sound.
- kaba0 4y agoNow it may be close to Java’s expressivity, 8 years ago. Now if they manage to cut down on verbosity it might surpass Java 8! How advanced!
- hsn915 4y agoI don't know that you can just add compile time nil checking to go and still retain everything else. It seems to me - although I could be entirely wrong - that the mindset that produces this kind of idea ("nil pointers are teh devil!") is incapable of producing the kind of experience that Go produces with its toolchain (trivial cross-platform compilation, etc). Again I can't prove it, but it just seems that way. For instance, if you believe nil pointers are the devil and you should statically enforce checking them at compile time, it seems that it would only be natural that you would also think the following other things are very important to be enforced at compile time: - Read-only references - Move semantics - And all the related baggage What does this have to do with compile times and cross compilation? Maybe not much, but time and attention are limited resources, and when you focus on concepts typical related with "nil pointers are evil" you take away precious resources that could otherwise have been dedicated to building the kind of developer experience that Go provides.
- bsaul 4y agoI really don’t understand why you got downvoted. That’s also my explanation of why they did it this way (which i don’t agree with, but they built a PL, i didn’t).
- brundolf 4y agoLots of languages have checked-nils without all the other stuff. TypeScript is one, Zig is another, Kotlin is another
- hsn915 4y agoZig is a good counter example to my argument, but there are things that Go does that Zid does not, namely, a runtime to manage: - Goroutines - Garbage collections I'm not saying these are good or desireable per se. The point is a bit more general: you can't just accumulate features without this accumulation having other effects on the language and its toolchain and causing degradations in other ways.
- mmarq 4y ago
- nu11ptr 4y ago> I do still have a weird feeling of getting back to the stone age whenever i get a nil pointer panic though. i wish go devs could figure out a way of fixing those last quirks without impacting the rest too much. Unfortunately fixing the "billion dollar mistake" as a retrofit is pretty much impossible without breaking backward compatibility. I see what they were trying for with nil and zero values, but IMO they should have introduced a "result" and "option" special type (or probably more Go-like would be separating nullable and non-nullable types via '?' like Dart did). If they did it like Dart, they could intro the concept without breaking backwards compatibility, wait X years until mostly adopted everywhere, and THEN break backwards compatibility by making it mandatory.
- eru 4y agoThey should have introduced sum-types. Or in C term: tagged unions that are checked by the compiler. They did the opposite when they designed the language, with their 'multiple return values', which are like tuples but only allowed in one special position in the language. But as you already suggested, tuples are the exact opposite of the "result" type you'd want here.
- throwaway894345 4y agoI would have much preferred sum types to generics. I can live with rewriting min() or using for loops over iterators or writing my own linked list; it’s a lot harder to safely (and performantly) work with data that can have a fixed set of shapes.
- eru 4y agoYou know how Go had generics for a long time, but only for the language designers who got to use it in functions like `make` or data structures like `map` or `slice`. There didn't used to be any generics for users of the language. Similarly, Go has tuples, but only for the language designers who get to use them for multiple return values from a function. No tuples to be used elsewhere where users of the language might find them useful. Now, Go also has sum types. But, yet again, only for the language designers: they get to stick `nil` as one of the constructors (to use Haskell terminology) in their favourite data types, but you as a language user don't get to make new sum types. Another example is operator overloading: the designers get to overload eg arithmetic operators, but you don't get to do that. In contrast C++ even for all its other faults at least makes an attempt to hand you many of the tools the language designers get. (Though, I like Rust's and Haskell's approach here more.)