Live data from Hacker News

Go Enums Suck

zarl.dev

131–140 of 244 posts

Re: Go Enums Suck

#131
post #46

Pascal in its original 1970's design, type myEnum = (value1, value2, value3, value4) Naturally that is too advanced and slows compile times.

Wirth regretted it later and didn't add it to Oberon. Quote from "From Modula to Oberon": "Enumeration types appear to be a simple enough feature to be uncontroversial. However, they defy extensibility over module boundaries. Either a facility to extend given enumeration types has to be introduced, or they have to be dropped. A reason in favour of the latter, radical solution was the observation that in a growing num…

> enumerations give rise to the exceptional rule that the import of a type identifier also causes the (automatic) import of all associated constant identifiers

I am confused by this assertion. I mean, if I had a module `Source` defining an enum:

    type MyEnum = (value1, value2, value3, value4)
and another module wanted to import it:

    import ( MyEnum ) from "Source"
I don't see how I have automatically imported all of the associated constant identifiers. Unless he was assuming that this would force me to import `value1`, `value2`, etc. as distinct identifiers? But it seems these ought to be namespaced inside `MyEnum`, e.g.

    MyEnum.value1
And one could easily imagine an import syntax to selectively import Enum values if desired:

    import ( MyEnum: ( value1, value3 ) ) from "Source"
Of course, I'm just making up syntax, but I hope the meaning is clear.

Re: Go Enums Suck

#132
post #74

Earlier quoted context omitted.

Enumerations back to integers. Enumerations can have iterators written on them that exhaustively enumerate the possible values. (Sum types either have no such enumeration at all, or in general, they're useless, so you don't see them.) Enumerations can be represented by a canonical and small set of strings, if you want a string backing them. This is what an enumeration is, partially because that's precisely what the w…

This still seems to point towards Rust's enums being both, no? Example: For a network protocol, see the first code sample I posted. For a `.Next()`, add the method. (I did this recently) Regarding sum types into a network not working, this again sounds like the wrapped enums. One way to do this is use an integer for the enum variant at index 0, and conditionally assign bytes of an appropriate size based on the type w…

OK, so now you are advocating for erasing the distinctions.

Why? Why is it so important that they be seen as the same thing to you? What benefit is gained from it? What benefit is gained from blending together a data structure that is fixed bit size from a family of data structures of variable size, a fairly fundamental difference? What benefit is gained from failing to consider the fundamentally different uses they are put to? What benefit is gained from looking at someone list a set of differences between the two, and basically saying, "yeah, they're different, but what if not?"

I can name further properties that differ between them. All sum types can embed arbitrary other existing sum types within themselves, without practical limit. Enumerations can not, because A: they may collide on which numbers they use and B: even if you remap them, you can run out of integers, especially with smaller values like byte-sized enumerations. Enumerations may have further structure within themselves, such that particular bits have particular meanings or values a certain number apart may have relationships to each other, or other arithmetic operations can be given some meaning; sum types themselves do not generally have any such relationships. (At least, I've never seen a sum type in two clauses of the sum type are somehow related; that'd be bad design of a sum type anyhow. Even if you did this to an internal integer contained in a sum type, it would be that integer composed in to the sum type that had that relationship, not the sum type.) Sum types have a rich concept of pattern matching that can be applied, enumerations generally do not (some languages can do some pattern matching with bits but there's still no deep structure matching concept in them).

I mean, how many differences are necessary before they are not the same thing? They can not fit into the same amount of memory; one is fixed in size, the other highly variable. One is simple to serialize into memory, the other has lots of complicated machinery. Each has operations generally valid on one but not the other (enumeration, pattern matching, sum type's composition whereas enums can not generally). The range of valid values (or domain, whichever you prefer) is not the same. There are languages that have enumerations without sum types, in that enumerations appeared in mainstream languages decades before sum types were a mainstream conversation. In what other ways could they be different?

It strikes me like arguing that ints and strings are the same, because honestly, what's the difference between 11 and "11" anyhow? Even if you're working in a language that strives to make the distinction as small as possible, you're still going to get in trouble if you believe they really are completely the same thing. And any programmer who goes through like truly thinking 11 and "11" are the same thing is in for a lot of confusion as concepts they should be understanding as separate, even if at times superficially related, are actually the same.

Re: Go Enums Suck

#133
post #80

> Go doesn’t technially have Enums and it is a missing feature in my book but there is a Go idiomatic way to achieve roughly the same thing. Oh, so it's a lot like Python then. > This is fine however it is nothing but an integer under the covers this means what we actually have is: Oh, so it's a lot like C++ then. > But what you notice here is we have no string representation of these Enums so we have to build that o…

Go is in this weird middle ground where it's modeled after C, so it's got things like no enums, return codes for errors, mutable everything, nulls, and pointers (that don't support arithmetic, so it's really just this "*" sigil that you have to remember to use sometimes), but it's also fully garbage collected and has built-in, stackful green threads. I have no idea what it's actually trying to be.

I would wager that the vast majority of backend software jobs are for people writing REST API microservices, exchanging JSON, with a mindset that is more practical and "blue-collar" than academic.

Golang is an absolutely ideal language for writing REST API microservices, that exchange JSON, with a practical and blue-collar mindset.

Plus it compiles to small-ish native executables. Which renders Docker superfluous in many uses cases, and also makes it well-suited for writing DevOps tooling (e.g. Docker, everything from HashCorp, etc).

It's not trying to out-cool Haskell and Rust on online message boards. But I would never in a million years evangelize either of those two languages for routine REST API work in most real-world shops, whereas I could suggest Golang without losing professional credibility.

Re: Go Enums Suck

#134
post #84

It's actually the coolest thing about Go enums, that they just it – enums. Developers with a background in other languages assume all enums' use cases need string representation. Well, no. They are needed sometimes, but not always. The same with the ability to pass int to the enum. Author says: > Anywhere that accepts an Operation Enum type will just as happily accept an int. Well, this is simply not true. [1] You'll…

>> Anywhere that accepts an Operation Enum type will just as happily accept an int. >Well, this is simply not true. As comment above [1] pointed out `printOperation(2)` is still valid. [1] https://news.ycombinator.com/item?id=39565640

Not trying to nitpick here, but '2' is not an int here. It's the constant evaluated at compile time. But yeah, valid case if users of your code are in the habit of typing magic numbers into your function that expects enum.

My understanding is that on a practical level, these kinds of issues arise from misusing types (or not caring about them) and naively putting variables of one type into the function that expects another. Examples with number constants typed in manually do not hold ground.

Re: Go Enums Suck

#135
post #5

I love Go. Especially how the devs stubbornly refuse to learn anything from Java, but stumble boneheaded into everything that Java solved over the years. Generics? We don't need that .. (time goes on) .. okay, damn it. Here! Generics! Enums? We don't need that, just do iota/integers! How long will it be this time until the Go devs accept that Java Enums are a safer and better abstraction over integers for the cases w…

Not even Java. The entirety of programming language development. Go is a language written by very good software developers but very bad language designers. It's an entire language of "why don't you just..." statements. Errors? Why don't you just return a value? Generics? Why don't you just use duck typing? Packages? Why don't you just use vendoring? In some cases these statements have some merit, but, as in most case…

> Go is a language written by very good software developers but very bad language designers

That's exactly why I love it so much

Re: Go Enums Suck

#136
post #122

Earlier quoted context omitted.

I know, and there is a reason why my favourite descendant from Oberon is Active Oberon, and not what Wirth pursued after 1992. Oberon-07 minimalism doesn't make Go better.

You can disagree with design philosophies, but Wirth and the Go designers probably have thought more about these things than you.

Appeal to authority.

Also note that none of Wirth's Oberon variants have achieved any commercial success.

Modula-2, which had enums, on the other hand did enjoy a limited success, across UNIX, PC and Amiga, and is nowadays even available as standard GCC fronted.

Go would have been a failure if the authors weren't Google employees, like it happened with their Limbo.

Re: Go Enums Suck

#137
post #94

func (o Operation) IsValid() bool { if o == Unknown { return false } return true } Why, oh why don't people just write return o != Unknown This is so common in the code that I'm seeing on the Internet, on GitHub etc. Is it because people don't understand booleans?

Most people aren't good programmers. And most also don't make a concerted effort to improve.

Sorry to say, but that's the simplest truth. Many go years and years in this industry with little improvement to quality/succinctness/readability. If you cared, and tried, you would.

Programming skill is uniquely distinct from domain knowledge, by the way. e.g. all of the research code written by domain experts that is full on spaghetti.

Re: Go Enums Suck

#138
post #117

It has always been surprising to me how primitive Go really is, for no really good reason. I understand the evolution of C, it made perfect sense back when it was invented. And the limitations were necessary due to the wide array of architectures and extremely limited computers of the time in every dimension (CPU speed, IO speed, RAM size, disk size, etc). Many of those dimensions have been improved by several orders…

You're right. Go is not simple, it is idiotically designed to deliberately exclude common sense features that ironically makes it less simple and more error prone to code in and read Go. Other languages are objectively better than Go for every imaginable use case. Rust is better for embedded. Kotlin is better for back end. I could go on. The creator of Go is very open and candid that he thinks his target audience, Go…

> sane error handling?

Golang _has_ sane error handling. It just considers errors a normal and expected situation.

When you perform a http request, and the result is successful you expect the result to be assigned a variable, right? Then why would you expect non-successful outcome to be returned in a different way? Why is it different? Why do you unwind the stack? Something terrible happened? Definitely not, it's as real life as 200 OK.

For unrecoverable things golang has panics, and if you don't like the idiomatic way of handling errors, you can just throw them like exceptions.

Re: Go Enums Suck

#139
post #132

Earlier quoted context omitted.

This still seems to point towards Rust's enums being both, no? Example: For a network protocol, see the first code sample I posted. For a `.Next()`, add the method. (I did this recently) Regarding sum types into a network not working, this again sounds like the wrapped enums. One way to do this is use an integer for the enum variant at index 0, and conditionally assign bytes of an appropriate size based on the type w…

OK, so now you are advocating for erasing the distinctions. Why? Why is it so important that they be seen as the same thing to you? What benefit is gained from it? What benefit is gained from blending together a data structure that is fixed bit size from a family of data structures of variable size, a fairly fundamental difference? What benefit is gained from failing to consider the fundamentally different uses they…

I'm not advocating for anything; I love Rust Enums and use whatever is close to them in other languages, which is usually better than the alternative of matching strings or similar (A convention in Python).

When I hear "These aren't really enums", my first reaction is to dive in and do research. (I'd been down this road before, probably after a similar HN comment...), but I haven't found usable or practical conclusions. It seems like the distinction is too subtle to be of use.

Stated more succinctly, let's call Rust enums "Choices", as I think this is causing semantic trouble. "Choices" are an excellent tool.

I'm looking at this from an engineering perspective; not a CS or abstract mathematics one.

I am curious what your pure Enum, and pure SumDataType look like in practice. I am also curious what existing implementations of either exist. Are they Haskell conventions?

Re: Go Enums Suck

#140
post #31

Earlier quoted context omitted.

> Rust's enums are great. Rust doesn't have enums. It has sum types – that for some reason it arbitrarily decided to call enums. Sum types are great. There is a good case to be made that Go would benefit from the addition of sum types. But until that day there isn't much more you can do with enums. That's all enums are – a set of named constants.

Sum type are great, but I don't think it fits in go type system.

They also tend to require proper pattern matching to be particularly useful, something which I can't see being added given Go's design philosophy.
Post reply on HN