10 ms·
There's something very seductive about languages like Rust or Scala or Haskell or even C++. These languages whisper in our ears "you are brilliant and here's a
by mustpax 12y ago
There's something very seductive about languages like Rust or Scala or Haskell or even C++. These languages whisper in our ears "you are brilliant and here's a blank canvas where you can design the most perfect abstraction the world has ever seen."
But, for systems programming, abstractions suck. They always, always have a cost. When abstractions break, you not only have to deal with a broken system but the broken abstraction itself too. (Anyone who has ever seen a gcc compiler error for C++ knows how this feels.)
Therein lies Go's value proposition. It does not make it possible to make things pretty (ugh, nil). It just makes it impossible (ok, really hard) to overcomplicate things. When you write Go code, you can picture what the C equivalent would look like. You want to deal with errors? Here's an if statement. Data structures? Here's a struct. Generics? Here's another if statement, put it inside your for loop.
Obviously, Go is not the right choice of language for most things. When you're doing application development, you may be able to afford the cost of abstractions. But for tools that only need to do one thing and do it extremely well, it's either that or C. And I'm not going back to managing my own memory anytime soon.
- wyager 12y ago>But, for systems programming, abstractions suck. Could you clarify what you mean by "systems programming"? To me, that means working with embedded systems, which Go is certainly not appropriate for.
- EpicEng 12y agoSystems does not necessarily imply embedded. I work in systems and, as far as I am aware, the term simply means software which primarily services the hardware (as opposed to the user). Drivers, HW interfaces, anything which has to make assumptions about the underlying hardware it is running on/servicing.
- mustpax 12y agoBy systems programming I mean writing the code that applications and distributed systems run on top of. Raft (https://github.com/goraft/raft https://github.com/goraft/raft) and groupcache (https://github.com/golang/groupcache https://github.com/golang/groupcache) come to mind as examples. That's a good point though. A lot of people mean different things by systems programming.
- frowaway001 12y ago> A lot of people mean different things by systems programming. Actually, no. It meant one thing until Go proponents tried to market their language and realized that their target audience didn't actually care.
- dsymonds 12y agoSeveral of the initial Go designers were doing "systems programming" in the 1960s under the exact same meaning. I'd also s/didn't actually care/got confused/ in your last sentence too.
- cjbprime 12y ago> Could you clarify what you mean by "systems programming"? To me, that means working with embedded systems, which Go is certainly not appropriate for. The blunt but approximately correct version is that embedded means that you're running on hardware that isn't powerful enough to run a Linux kernel. Systems programming just means you're working below the application layer. So if you take your laptop and write a device driver, or work on filesystem or networking code, you're doing systems programming without doing embedded.
- waps 12y agoJust curious : how does one run go without a linux kernel ? (without a kernel at all, please, I know about the freebsd port)
- cantankerous 12y agoYou'll probably be looking for a Go runtime that fills a kernel shaped hole. Without a kernel, where do all your syscalls go?
- waps 12y agoYes but the point of the parent poster was that go can work on minimal embedded systems, which to my knowledge it cannot, so I enquired.
- lmm 12y agoNo, the point of the parent poster was that "systems" is not the same as "embedded", and that while go may not work on the latter it can work on the former.
- pcwalton 12y ago> When abstractions break, you not only have to deal with a broken system but the broken abstraction itself too. (Anyone who has ever seen a gcc compiler error for C++ knows how this feels.) Using C++ template error messages to attack generics in Rust and Haskell is pretty weak, because typeclasses were explicitly designed to avoid the problems of "ad-hoc" templates in languages like C++. Error messages are in fact what typeclasses are really good at.
- kryptiskt 12y agoType classes are so good at error messages that they were proposed as the solution to the error message mess in C++ in the form of Concepts.
- fpgeek 12y agoAs someone who's spent more time than I'd like to remember improving type class error messages, this sentence boggled my mind. Then I remembered what C++ template error messages are like and it all made sense again.
- mustpax 12y agoThere's no question that Rust and Haskell have better tools than C++ for abstracting code. Go is just demonstrating that you can write great software without the aid (and cost) of generics.
- fpgeek 12y agoWhat is Go demonstrating about programming without generics that Lisp, Java (pre-2004), Python and tons of other languages haven't already demonstrated?
- oscargrouch 12y agoNothing, thats the point.. its not language that the creators did because they are vain, or want to prove they are smart, or know what beauty is.. its a language that are created to get things done! the beauty of it its the same beauty that we see in Unix or C.. its simplicity.. Dear God.. I dont know why so many programming languages anyway to do the same thing all over again.. just because of the sake of the sintax or the type system.. or because the guy fell sooo smart because hes using FP.. so he can fell instelectually superior to all human beings Since C.. its all the same programming paradigm.. the rest is just detail.. the only langs that have its own way that are not cover by the C paradigm are Lisps Really my language of dreams.. will be to use notes like in a music sheet.. this is a really different paradigm.. or use DSP with just I/O signals.. this is something new.. the rest is just vanity.. And i dont want to be the rat lab of some language designer full of himself, that doesnt think of me, the poor programmer that has to maintain the code in the lang he creates!! This is the unix philosophy... theres too much noise, im sure these are the kind of things that make people run away from technology... We need to somehow find our way to simplicity.. for our own sake
- dualogy 12y ago> Generics? Built-in slice and map types cover most real-world needs quite neatly anyway.
- bjz_ 12y agoFor some applications. But once you start venturing into the realms that Rust is targeting, having user defined generic data structures is very important.
- MartinMond 12y agoDoesn't Go have a GC? How can you then "picture what the C equivalent would look like"? Yes there are GCs for C, but is anyone successfully doing "systems programming" (whatever that may be) in C with GCs?
- mustpax 12y agoThat's true. It's not just GC actually. Slices and goroutines don't have a direct analogues in C either. But it is fairly easy to reason about the runtime complexity of these conveniences. But like I said, if I didn't care about GC or concurrency, I'd be writing C.
- logicchains 12y agoIsn't the C equivalent of a slice just a struct containing a *T, a length and a capacity?
- aktau 12y agoAnd some methods for manipulating it (slicing it), and reference counting. And macro's for automatically ref'ing/unref'ing.
- logicchains 12y agoReference counting? I didn't know reference counting was used with slices, I thought they just used the GC.
- aktau 12y agoYes, but since C is not a GC-language, I thought I'd add that to reach more equivalence :).
- tinco 12y agoI don't agree with the GP, but if Go were very similar to C and the only big difference would be that C has no GC it would pretty easy to picture what the C equivalent of Go code would be. Exactly the same but with calls to `free()` at the end of some functions. (or preempted between instructions at unpredictable places) Don't make GC's a bigger deal then they are. They are a tool to remove the need to call `free()` at the right time, with the downside that you don't get to control what the GC thinks is a right time instead.
- Dewie 12y ago> These languages whisper in our ears "you are brilliant and here's a blank canvas where you can design the most perfect abstraction the world has ever seen." They also tell me "now you don't have to wait for the language designers or compiler writers in order to 'implement another feature'." Not that _I_ would necessarily be this "brilliant" guy that implements these features. Most likely I will just find some third party library that does it.
- oscargrouch 12y agoThe problem is when you have to maintain your code with millions of lines, and hundreds of abstractions.. those "features" will hunt you in your nightmares at night This is the "The Curse of C++" and some languages pointed in the article while beautiful and correct at first sight are going down in the same road.. Do we use a programming language to look smart, to create correct code or to efficiently solve problems in a maintanable and sane way? Go is pragmatic.. theres nothing wrong with that.. but i agree that adding some features to it would not hurt either (like generics and enums) :)
- jerf 12y agoTo understand a language, one must know what problem it was designed to solve. It isn't always obvious, or what it initially looks like it was designed to solve, or even what the community thinks it was designed to solve. Erlang, for instance, isn't about concurrency. It's about reliability. Go, I think, is also not about concurrency. It's about building a language that can be sanely used by reasonably large groups of people of varying levels of skill, yet still produce fairly good software even so, without the language forcing a complexity explosion to deal with it. Consequently, this does not appeal to a lot of relatively skilled programmers used to programming alone. It isn't my personal pick of favorite language, for instance. However, if I could push a button for free, I would convert my workplace of a couple hundred developers to it in a heartbeat, whereas I probably wouldn't actually do that with my favorite language. It is not, of course, a magical fountain of code quality, but it would give me the best tools and best foundation to clean up code bases that in all the other candidate languages I know are one or another sort of mess. If I were starting a new startup right now and Go were even remotely appropriate, I'd use it. But in my hobby projects? Not really. Except maybe to smash out a microwebsite, it's pretty good there. So, you know, a lot of the question is what exactly are you looking for in a language? I like Haskell, but the idea of even proposing to change a project at work to it is laughable... and this is important... nor would I expect to enjoy the result two years later if I won. The mess of code that would result from people hitting Haskell with a stick until it did what they wanted it to do would be an unstoppable torrent of ill-conceived code. On the other hand, Go would almost certainly produce much cleaner code, because that's where it really shines. Maybe it isn't "good", but it's the best choice right now in a lot of places. (It's interesting to contrast Go's approach to this problem with the other major language to tackle this problem space, Java. Despite attacking the same problem, the approaches are significantly different, and I think Go's way better. I'd hesitate to actively predict this, but Java could definitely be feeling some heat from Go in three to six years in a way that very few languages have actually managed to provide any challenge to Java in a long time.)
- Mr_P 12y agoThese two statements made me cringe: > But, for systems programming, abstractions suck. They always, always have a cost. > Generics? Here's another if statement, put it inside your for loop. If you care about speed (and many systems programmers do), this is exactly the opposite of what you want to do. Unlike your proposal of putting potentially-costly if-statements inside of for loops, generics/templates in c++ provide zero-cost abstraction (in terms of execution time. If you think dealing with the error messages presents too high cost in terms of developer-time, switch to clang).
- mustpax 12y agoExactly! Go makes the cost of generic code explicitly visible. Generics encourage over-generalizing behavior that runs counter to writing highly performant code. If you care about speed, you don't spend time making your code generic. You optimize closely to your use case.
- wyager 12y ago>Go makes the cost of generic code explicitly visible. Generics encourage over-generalizing behavior that runs counter to writing highly performant code. I think you may be missing some info regarding generics in Rust and Haskell. As I mentioned in the article, there is zero runtime overhead for generic programming in Rust and Haskell. Zip. Zilch. Nada. That's why their constraint-based static generics system is awesome.
- mustpax 12y agoLack of generics is part of the reason why Go is easier to learn and the Go compiler is faster than, say, Rust. Sure, generics don't have runtime overhead in Rust and Haskell but they have other costs. You always pay for abstractions some way.
- orclev 12y agoBased on this logic I assume you code in nothing but machine code? After all even assembler is an abstraction and therefore must have a cost. Heaven forbid you should do something as extravagant as use C for something, that level of abstraction (all those long jumps and stack manipulations, oh my) must positively destroy performance. Do you also happen to program using the gentle flapping of butterfly wings to disturb air currents and redirect cosmic rays?
- dllthomas 12y ago"But, for systems programming, abstractions suck. [...] But for tools that only need to do one thing and do it extremely well, it's either that or C." C and Go are just two particular piles of abstractions. The tools work better for some problems, but that's not because "abstractions suck" for those problems.
- briantakita 12y ago> These languages whisper in our ears "you are brilliant and here's a blank canvas where you can design the most perfect abstraction the world has ever seen." These languages have built-in abstraction tools (templates) that you can use to create your own abstractions. What I like about Go is the abstraction tools are primitive and allow for consistent & precise expression. The expression may not be as concise in certain cases, however, you can build in the mechanisms into your architecture. > But, for systems programming, abstractions suck. They always, always have a cost. When abstractions break, you not only have to deal with a broken system but the broken abstraction itself too. (Anyone who has ever seen a gcc compiler error for C++ knows how this feels.) That is why custom abstractions to your problem domain are important. A framework or a language with lots of features will get you started quickly by providing out-of-the-box tools that you can hang your program architecture on. However, I prefer to have a custom architecture & idioms which are appropriate to the current domain & evolution of the domain.
- coldtea 12y ago>What I like about Go is the abstraction tools are primitive and allow for consistent & precise expression. Well, not really consistent. For example, try having a range loop for your own structures. Or something like make for them. And not really precise. The need for interface{} and type switches in idiomatic Go code throws preciseness out of the window.
- waps 12y agoThey claim this is a feature, not a bug. It means that range will never block or do weird stuff. Except of course when it does (bastard question for those who think they know : what does range do on a nil channel ?) Despite all these clarity claims, go has significant pitfalls, like the nil channel above (and you will enounter nil channels). There's other things, like "what is a pointer in Go", if your answer involves "*", I urge you to reconsider (hint : what's the difference between []int and [5]int ? Is one of them a pointer ? What about channels (of course I talked about nil channels) ? Maps ? But every type can be typedeffed to a pointer type of itself, like in Pascal (lots of things look like pascal), and result in completely unpredictable reference or value semantics (or my favorite : partial reference semantics). Does go have generics ? YES (make, range, ...). Go has something no other language has : return type generic function types (meaning a functions meaning changes depending on what you assign the result to, like range). Does Go have operator overloading ? Is Go object oriented ? YES (including single inheritance). YES. Does go have (complicated language feature X) ? Probably yes. But all of these features are only accessible to Rob Pike, who has apparently decided that nobody has any use for any kind of tree or graph data structures, matrices, complex numbers, or so. In practice you can catch the go team themselves in errors on the language semantics in their presentations, so I think a VERY strong case can be made that it's not at all that obvious. But the truth is : this language, due to politics (high position of it's inventor) has 10 or so FTE behind it, with lots of paid people contributing various small bits. Is it anything more than some guys idea of his own favorite programming language ? The honest answer is simply : no. The only real advantage Go has is a small, yet functional and pretty complete standard library (like C++ had in the 1980s). It is an advantage that will fade, just like it's faded for every other language.
- jules 12y agoThis is incorrect. Generics in C++ are zero cost, since they are specialized at compile time. On the other hand if you want to write generic code in Go you have to use Object types everywhere. That means that objects have to be tagged, those tags checked with run time checks, additional pointers everywhere, bad memory layout, etc. So generic code in Go is significantly slower than in C++.
- rcxdude 12y agoIt depends on how you quantify cost. There isn't any performance cost, yes (which is what 'zero-cost abstractions' usually means in C++), but there is a) an increase in code size, and b) an increase in complexity/difficulty of understanding of implementation (and to some extent use). These may be good tradeoffs to make (in many of the areas where C++ is used they make sense), but I think 'zero-cost' is a disingenuous way to put it.
- robryk 12y agoThere might actually be a performance cost due to increased code size (by way of increased amount of icache misses).
- jules 12y agoThe implementers of MLton, an ML compiler that does C++ style monomorphization, found that after optimization the code size is actually smaller with monomorphization. That's because the specialized code is simpler and can be further optimized. So even if you have multiple specialized copies, the total is still smaller. See here: http://mlton.org/Performance http://mlton.org/Performance
- jules 12y agoHow are generics more difficult to understand than hacking your own mechanism together with casts? That is something I do not understand.
- KMag 12y ago
- bad_user 12y agoI'm not writing the following to make people pick another language - if Go is suitable for your project in terms of features, runtime, tools and community, then by all means use Go. It's a fairly decent platform to target and it can further evolve to meet more stringent needs. But if we are talking about the cost of abstractions, the biggest elephant in the room is that Go's GC is NOT optional, which makes it unsuitable for ... (1) systems programming and (2) real-time systems. C++ and Rust do not suffer from this. And Go is not even suitable for soft real-time systems, because for that you need a GC that never stops the world - right now Go is even less suitable than Java in this regard, because at least for Java you've got the pauseless GC from Azul Systems. > "But, for systems programming, abstractions suck. They always, always have a cost." That's a logical fallacy, because if all abstractions suck, then why aren't we doing "systems programming" in assembly (were systems programming is whatever the definition du-jour you prefer to fit Go in)? Clearly, it depends on the project on where it can draw the line, since we are always doing compromises for gained productivity, no? And going back to the non-optional garbage collection that's not even suitable for soft real-time systems, it kind of makes the point on Go avoiding higher-level abstractions on purpose kind of bullshit. > "It does not make it possible to make things pretty (ugh, nil)." It's not about pretty-ness, it's about correctness - which in a language containing memory unsafe constructs that can lead to billion dollar bugs (i.e. Heartbleed), is a freaking huge deal. Rust is very innovative in this regard, because it's a systems programming language that solves many issues by means of its more advanced type system - and surely no type system is perfect, but even a single bug that's caught by the compiler, that's a bug that won't reach production. > "It just makes it impossible (ok, really hard) to overcomplicate things." I wish developers would stop equating "complicated" to things "I don't understand". That's not what complicated means. Here's the definition: "consisting of many interconnecting parts or elements". That Go doesn't allow certain higher-level abstractions, that's in itself a recipe for complications. > "for tools that only need to do one thing and do it extremely well, it's either that or C. And I'm not going back to managing my own memory anytime soon" The choice between C and Go, given that Go is garbage collected, is a false dichotomy.
- frou_dh 12y ago> I wish developers would stop equating "complicated" to things "I don't understand". Rich Hickey's presentation on this topic should be required viewing for everyone: http://www.infoq.com/presentations/Simple-Made-Easy http://www.infoq.com/presentations/Simple-Made-Easy