11 ms·
Go Enums Still Suck
- Thaxll 2y agoIn most languages enum suck, it's not specific to Go, lot of pitfall and ABI issues, even my modern languages like C# have those.
- randomdata 2y agoYes, enums fundamentally suck. There is nothing you can do in a language to make them not suck other than to get rid of them... ...which, indeed, is quite viable as enums are just a hack to work around a limited type system anyway.
- benreesman 2y agoI have a mountain of respect for Bell Labs and its contributions to the public welfare, and a lot of respect for the current group of alumni, mostly at Google, and mostly affiliated to a greater or lesser degree with golang. I have my differences with one or two of them (Pike telegraphs a wildly overcompensated imposter syndrome, but he’s almost as much of a genius as he acts like he is and who am I to judge on an overcompensated imposter syndrome, moreover when the guy in at the next desk over is Ken Thompson, who wouldn’t be a little intimidated by the legend). With that said, golang is too opinionated for its level of adoption, too out-of-touch with emerging consensus (and I’m being generous with “emerging” here, the Either monad is more than an emerging consensus around the right default for error handling), and too insular a leadership to be, in my personal opinion, a key contender outside some narrow niches. I’m aware that there are avid advocates for golang on HN, and that I’m liable to upset some of them by saying so, so I’m going to use some examples to illustrate my point and to illustrate that I’ve done my homework before being critical. Many, including myself, became aware of what is now called golang via this presentation at Google in 2007 (https://youtu.be/hB05UFqOtFA https://youtu.be/hB05UFqOtFA) introducing Newsqueak, a language Pike was pushing back in the mid-90s with what seems to be limited enthusiasm no greater than the enthusiasm for its predecessor Squeak. Any golang hacker will immediately recognize the language taking shape on the slides. I’ve been dabbling with golang for something like a decade now, because I really want to like it. But like a lot of the late labs stuff it seems to have suffered from the dangerous combination of the implications of Richard Gabriel’s Worse is Better observation: it was simpler, faster, cheaper, and ultimately more successful to incrementally adapt innovations from Plan9 into Linux (and other Unices), to adapt innovations from sam and acme into nvim/emacs (and now VSCode), and to adapt channel-based and other principled concurrency from Newsqueak/golang (not to mention Erlang and other more full-throated endorsements of that region of the design space) into now countless other languages ranging from things like TypeScript and Rust at the high end of adoption all the way to things like Haskell at more moderate levels of adoption. Ironically enough, the success of UTF-8 (a compromise for the non-ASCII world but the compromise that made it happen at all) is this same principle in action via the same folks! And golang would be fine as yet another interesting language serving as a testbed for more pragmatic applications of radical ideas: but it’s got corporate sponsorship that puts Sun Microsystems and Java to shame in scale and scope, but done quietly enough to not set off the same alarm bells. The best example of this is probably this GitHub issue: https://github.com/golang/go/issues/19991 https://github.com/golang/go/issues/19991 (though there are countless like it). I’ve worked with Tony Arcieri, he’s brilliant and humble and hard-working and while we haven’t kept in touch, I keep an eye out, and he’s clearly passionate about the success of golang. But proposal after proposal for some variation of the Either monad has died on procedural grounds for nearly a decade, all while being about the only thing that everyone else agrees on in modern industrial PLT: TypeScript supports it, Rust supports it, C++ de-facto supports it via things like abseil and folly, and of course the hard-core functional community never even bothered with something worse in the modern era. You can even kind of do it, but there are intentional limitations in the way generics get handled across compilation units to ensure it never gets adopted as a community-driven initiative. Try if you don’t believe me (my golang code has a Result type via emacs lisp I wrote). Another example is the really weird compilation chain: countless serious people have weighed in here, I’ll elide all the classics because most people making these arguments have their own favorite language and they’ve all been on HN dozens of times, but a custom assembly language is a weird thing to have done, almost no one outside the hardcore golang community thinks it’s sane, the problems is creates for build systems and FFI and just everything about actually running the stuff are completely unnecessary: there are other IRs, not all of them are LLVM IR if you’ve got some beef with LLVM IR, and given that go doesn’t seriously target FFI as more than a weird black sheep (cgo) there’s, ya know, assembly language. It’s a parting shot from the Plan9 diehards with the industrial clout to make it stick. The garbage collection story is getting better but it’s an acknowledged handicap in a MxN threading model context, it’s not a secret or controversial even among the maintainers. See the famous “Two Knobs” talk. Raw pointers, sum types, dependency management, build, generics that never get there, FFI: solved problem after solved problem killed by pocket veto, explained away, minimized, all with mega-bucks, quiet as a gopher corporate sponsorship fighting a Cold War against Sun and the JVM that doesn’t exist anymore marketed by appealing to the worst instincts of otherwise unimpeachable luminaries of computing. There is great software written in golang by engineers I aspire to as role models (TailScale and Brad respectively as maybe the best example). I had to get serious about learning golang and how to work around its ideologically-motivated own-goals because I got serious about WebRTC and Pion (another great piece of software). But it sucks. I dread working on that part of the stack. Go enums do suck, but that’s because we pay a very heavy price for golang being mainstream at all: we’ve thrown away ZooKeeper and engineer-millennia of garbage-collector work and countless other treasures, it sucks oxygen out of the room on more plausible C successors like D and Jai and Nim and Zig and V and (it pains me to admit but it’s true) Rust. Yes there is great software in golang, tons of it. Yes there are iconic legends who are passionate about it, yes it brought new stuff to the party and the mainstream. But the cost was too high.
- Mawr 2y ago> and I’m being generous with “emerging” here, the Either monad is more than an emerging consensus around the right default for error handling It is clearly the right way, but Go's error handling already has 80% of its benefits. Switching over to a Result type at this point would require a lot of churn for little benefit. Sum types on the other hand... > it sucks oxygen out of the room on more plausible C successors like D and Jai and Nim and Zig and V and (it pains me to admit but it’s true) Rust. D is dead, never even heard of Jai, Nim hasn't caught on, can't believe you're mentioning V. Rust competes mostly with C++ and is unlikely to appeal to C enthusiasts. Zig is promising, but it's in very early stages. Go is used because it fills the glaring hole of a reasonable, modern, fast and GCd language. It reflects poorly on PL designers that we don't have a properly designed modern language in the space and have to make do with Go. Some combination of Go+Rust would be perfect, but it just does not exist.
- randomdata 2y ago> It is clearly the right way It's clearly not. Either<T, Err> creates a dependence between T and Err that should not exist. They are logically independent variables. The state of Err has no reason to imply anything about the state of T. I'd be inclined to agree that, for all practical purposes, it is the best we've got, but that doesn't mean it is right. An ideal language can do better.
- pjmlp 2y agoI am doing pretty well with ML derived languages, or its influence in JVM/CLR offerings + GraalVM/OpenJ9, thankfully I only get to deal with Go on DevOps related tooling, and some of it has already been rewritten into Rust.
- 0xjnml 2y agoGo does not have enum types and Go does not have [Pascal-style] subrange types. The correct title should read "Go named constants suck", but then I'm not sure what's wrong about them.
- deleted 2y ago[deleted]
- perbu 2y agoI'm wondering if it be better if an iota would assign random, unique numbers at compile time, just to make it clear that these are not entirely safe identifiers inbetween compilations.
- datascienced 2y agoIf only there were a way in computer science to guarantee you couldn’t misuse a value. Then you wouldn’t need to rely on using UB to scare people into not making a mistake. (A dig at Go not your comment :-)
- logicprog 2y agoYeah, if only there were decades of programming language design research and field testing since C for Go to draw on...
- foldr 2y agoIota does have other uses where this behavior wouldn't work, such as for defining bitmasks: const ( Flag1 = 1 << iota Flag2 = 1 << iota Flag3 = 1 << iota ... ) The magic const shorthands even let you omit the explicit definitions for everything after Flag1, but I think it's easier to get the idea when all the definitions are explicit.
- neonsunset 2y agoOr, you know, it could learn a thing or two from C# enums (which are not even that good): [Flags] public enum Options { Default = 0, Option1 = 1, // can also be defined as 1 << 1 Option2 = 2, // can also be defined as 1 << 2 Option3 = 4 // can also be defined as 1 << 3 } The above is a choice, and an enum can be defined normally if it's not a bitmask. .ToString() would even format it correctly if multiple flags are toggled, it can be easily parsed with Enum.Parse<MyEnum>(text) and more. And hell, this is just tolerable implementation. It makes a lot of sense given historical context of C enums, which it's a direct improvement over, but not a step away in what is now considered to be the right direction represented by Rust enums instead. (Luckily, unlike Go, C# allows to trivially define Result<T, E> class/struct and a method on it in the form of Map(ok => .., err => ...))
- Alifatisk 2y agoWhat's up with the horizontal scroll?
- dewey 2y ago[flagged]
- bowsamic 2y ago[flagged]
- bheadmaster 2y ago[flagged]
- axitanull 2y agoIt just dawns to me that "complaining about the style or minor usability of the website" is a type of bike shedding that happens regularly in hacker news. Instead of contributing to the discussion related to the post, it's easier to just go "the website sucks."
- ayhanfuat 2y agoI don't think it is a minor annoyance. It is indeed very hard to read.
- axitanull 2y agoSo to continue our bikeshedding: Hacker News has no shortage of resourceful people that can silently handle the issue by themselves (the first comment even said themselves that they could simply use Reader Mode!). But the main point of my reply is: look at the number of replies that focus on the style of the website, and compare that to the number of replies that focus on the point of the post/article.
- randomdata 2y agoThere is no point to the article, though. Enums suck in every language that have them. There is good reason why many modern languages don’t have them at all, offering sum types instead. It doesn’t add anything to the conversation.
- kaba0 2y ago[flagged]
- leosanchez 2y agoPersonally I dislike go because of its type system. But I can see why people like it.
- bayindirh 2y agoIt's a simple, minimal language which does a lot of things right. I see it as a better C when you don't need to touch hardware or OS kernel. It's great for writing small utils, or doing multithreaded things in general. I don't understand qualms against programming languages. It's a tool. Best one is chosen for the task at the hand and applied to the problem. That's all.
- neonsunset 2y agoThis comment is an easy tell. It's so prevalent. Because no one looked at how Go works, what Go does and what its overhead is. Not even mentioning, rightfully pointed out, a complete joke of a type system that completely disregards any improvements made since 80s.
- bayindirh 2y ago> Because no one looked at how Go works, what Go does and what its overhead is. I develop using Go, thanks. > Not even mentioning, rightfully pointed out, a complete joke of a type system that completely disregards any improvements made since 80s. One of the designers of Go is Rob Pike, who's worked on C, UNIX and Plan 9. I think the language embodies the core principles put out by these "things" pretty well. If we're talking about "development time overhead" of Go, initial momentum building is a bit slow, but after it starts rolling it's deviously fast. If we're talking about "runtime overhead", I can say it's "fast enough" for what it's designed for. If we're talking about "storage overhead", you can always dynamically link it.
- cupofjoakim 2y agoI'm having some real issues with legibility on this page. I'd like to encourage the author to decrease the font size, increase the line spacing and look into a smaller max-width for the paragraphs. It'd also be nice to have some spacing before a new sub-heading. I'm coming from a 4k screen, so that does play into it, but i honestly just could not read the article without changing the text properties here.
- chimeracoder 2y ago> I'm coming from a 4k screen, so that does play into it, but i honestly just could not read the article without changing the text properties here. It's not just using a 4K monitor. It's very difficult to read on mobile as well (and even harder to change properties there, short of reader mode).
- deleted 2y ago[deleted]
- ergonaught 2y agoI see literally nothing in this post that elaborates on "Go Enums Still Suck".
- axitanull 2y agoThe first sentence literally points out that the post is a continuation of previous post that elaborates on why Go Enum sucks.
- Brian_K_White 2y ago...and then does not show in what way they still suck. Or was it just very dry and although the text did not say so explicitly, the examples did some how show go enums in the act of sucking?
- kubb 2y agoIt would be a very significant improvement to have tagged unions in the language.
- dgb23 2y agoWhen I played around with zig, I got a much better understanding what they actually are and how they are (or can be) represented in memory. It's a language that lets you actually feel what your program is doing.
- otteromkram 2y agoYou didn't seem to be criticizing C#, though?
- kubb 2y ago??
- Sharlin 2y agotype planet int // Gravity[float64],RadiusKm[float64],MassKg[float64], ... Sorry, but what? Is this really an ad-hoc DSL embedded in a regular comment that's then preprocessed by… something, to generate the actual Go code? Certainly there's something that sucks here! Edit: I'd find it marginally less sucky if there at least were some special prefix like `//#` or `//my-preprocessor` or whatever to mark magical semantically significant comments. And what's the deal with the `field[type]` syntax that seems totally ad hoc, why not use the standard Go syntax `field type`?
- xienze 2y agoThere’s a history of this sort of faked annotation thing in Go. The most notable example being comments used to denote how a struct’s fields are mapped to/from JSON.
- kelnos 2y agoThe struct field tags thing (which are not comments) is at least something built into the language, that other code can access via reflection. Not being able to do this for this use-case, and having to rely on comments that are preprocessed by a code generator, is just a shame.
- vsnf 2y agoMaybe it's slightly better than total shit, but it's still pretty shit. Half the struct field tags aren't even typechecked, and will force you to go on hours long goose chases wondering why something isn't working only for you to realize eventually that 'someField string `db_orm_field_1:"0"' is actually supposed to be '"someField string `db_orm_field1:"0"'.
- neonsunset 2y agoSomething like this just doesn't happen in C#. Neither in runtime reflection based ORMs nor in code generation based (micro)-ORMs (which, unlike Go, does not need extremely clunky manual scripting and "just works").
- Sacro 2y agoGo doesn't have enums.
- randomdata 2y agoIt doesn't have what Rust mistakenly calls enums - what everyone else in the world calls sum types, but it most definitely has enums in the traditional sense. Enum normally refers simply to assigning a number to something. That is what iota does.
- pjmlp 2y agoEnums in the traditional sense, is what Pascal and C have been doing it for decades. (* Pascal in 1970 *) Planet = (Unknown, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune); // C in 1989 enum Planet {Unknown, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune}; Plus type system guarantees, and in Pascal's case, run time capabilities to query enum values and ranges. Go's hack has barely anything to do with that.
- randomdata 2y agoYes, those examples too assign a number to something. Enumeration is not a new concept. In fact, it's an incredibly old concept that emerged in programming langauges as a hack to work around our, a the time, limited understanding of type systems. A modern type system has no reason for enums at all. Of course, Go purposefully tries to be an 'old' language, hence why it copied the antiquated pattern of providing assignment of numbers as a language feature.
- pjmlp 2y agoYou mean it copied how programming used to be before 1970's. Great achievement.
- randomdata 2y agoNot really. Enums as a programming language construct are a 1970s invention. Funnily enough, Algol 68 had sum types, although controversially so due to overhead concerns. If only Go had copied the state of programming before 1970, then we wouldn't have to listen to all the nonsense about enums sucking. Of course they suck – they are, and always will be, a hack to work around a limited type system.
- baby 2y agoGolang doesn’t have sum types is Golang’s biggest problem, not generics
- klabb3 2y agoYup. I love Go but they didn’t get types right. The level of abstraction is too low, and embedding and iota never feel quite right. Rust got the basics right. Pattern matching, no nulls, traits, sum types, and the sugar around try with the ?-notation is also great. Despite it all, this is not a dealbreaker, and Go shines for striking a great balance of a sensical language. But I always cringe a little inside when fanboys defend even the most awkward and annoying aspects of Go.
- pjmlp 2y agoAs someone that also has to wear DevOps hat, I really would like that Rust had matured first. At least newer CNCF projects aren't going into Go as much as they previously did.
- dist1ll 2y ago> embedding [..] never feel quite right. funnily enough, I would argue that struct embedding is one of the things that Go actually got right. It's simple and elegant, and I think it could've been a useful addition to Rust.
- klabb3 2y agoYeah to be fair I don’t think I even have a problem with embedding per se. It’s quite nice. It’s more the fact that embedding can be used to work around missing type system features. I can’t recall exactly, but I remember using embedding for things that it probably wasn’t designed for, because it would save me a ton of boilerplate.
- dontlaugh 2y agoAlmost every single case of embedding I've encountered was buggy in some way. Explicit composition is much more reliable.
- sethammons 2y agoI see it a lot: there is a type of developer who loves brevity in writing of the code. It is critical to them. They believe that productivity is hurt with more verbose code. They optimize for writing. Depending on the project, maybe that is ok. I work on projects with multiple teams and zounds of developers. In this sphere, productivity is NOT increased with these kinds of things as they save moments during writing but cost more during onboarding and reading. The more you have to keep in your head to make the code make sense, the harder it is for new team members to spin up. Productivity in the kinds of orgs I work in is improved when individuals can look at a small section of code and understand it directly. If you are going up call chains to understand things, you are costing productivity. When you have to slow down and mentally parse something, you are costing productivity. I would take a hand written and hand maintained version of what this utility has as output over the utility every single time.
- ikari_pl 2y agoThe more code I need to READ to understand what I'm looking at, the less optimized for maintenance it is. If it takes 5 lines to understand that the map I'm looking at is effectively used as a set, it's worse than if I had a Set abstraction. Of course now I do, 20 of them, because when there's no built in, there will be packages made by the community.
- sethammons 2y agoCongrats, you just inherited this code and have to fix it: Mercury 0.378,2439.7,3.3e23,57910000,88,0.0000000001,0,false There is no way to infer what any of the values are. They are practically magic numbers. How do you know if you swapped a pair of numbers there and what that will do to the application? You have to mentally map all those things. It is vastly, overwhelmingly more new-dev friendly to use: MERCURY: Planet{ planet: mercury, Gravity: 0.378, RadiusKm: 2439.7, MassKg: 3.3e23, OrbitKm: 57910000, OrbitDays: 88, SurfacePressureBars: 0.0000000001, Moons: 0, Rings: false, },
- 2y ago
- jjice 2y agoI went years without using a language with sum types and was fine. As soon as I was exposed to them, I was hooked. They just make so much sense in so many places, especially in trees. It seems that over the past five or so years, they've been adopted more as pattern matching has. If they're not an explicitly feature of the language, then they can be replicated (like with Java sealed classes). I'm not sure if Go would ever implement them, or add something that we can more easily replicate sum types with, but god damn are they my favorite language feature that so few languages properly support. I wouldn't have expected Go to implement them, but after generics and range over functions, I feel like anything could be game.
- rightbyte 2y agoA nullable pointer is a sum type and Go has them.
- pjmlp 2y agoGo doesn't need to go full speed on sum types, plain basic Pascal enumerations from 1970 instead of that hacky iota/const dance, would be a huge improvement already.
- randomdata 2y agoThere is no practical difference between enums in Pascal and Go. What is different is that Pascal added an additional layer over enumerations – what is basically a poor man's sum types – to hide that there are enums under the hood. In fact, one has to perform an explicit conversion if they want to access the enum. Sum types predate enums, and no doubt they were trying to stay close to sum type semantics without the overhead. Something later languages, like C and Go, chose to forego in favour of exposing the enums naturally. But if you're going to go to all the trouble of implementing a poor man's sum types, why not just do it properly? It's not 1970 anymore. We've solved the overhead problems. Sum types are perfectly viable these days.
- pjmlp 2y agoOf course not, first Go would need to actually have support for proper enumerations. Go neither has the 1970 Pascal enumerations, nor the 1976 ML sum types. Both approaches too advanced to implement on 2009, apparently. We don't want the poor minds Go is targeted at, as per Rob Pike's words, to have imposter syndrome learning the language. As it is, is a non starter to even bother.
- coxley 2y agoWhat enums?
- pjmlp 2y agoMeanwhile in the 1970's.... type Planet = (Unknown, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune); PlanetContainer = record gravity: real; radiusKm: real; massKg: real; orbitKm: longint; orbitDays: integer; surfacePressureBars: real; moons: integer; rings: boolean end; var planets : array [Planet] of PlanetContainer;
- nurettin 2y agoand const PlanetIndex = 1..9; Innersolarsystem = Mercury..Earth;
- deleted 2y ago[deleted]
- ptman 2y agoHow does this compare to enumer? https://github.com/dmarkham/enumer https://github.com/dmarkham/enumer
- binary132 2y agoYes. And?