Live data from Hacker News

Enums in Go

dizzy.zone

31–40 of 57 posts

Re: Enums in Go

#31
post #18

The problem isn't so much the lack of enums, it's more that there is no way to do exhaustive pattern matching at compile time. I have seen production systems go down because someone added a variant to an 'enum' but failed to handle that new variant everywhere.

In theory yes. But practically there are always locations where we can't match every case, so we either have to live with a warning or add a catch-all arm. And as soon as a catch-all arm exists, we are in "not checked any more" state, but with a compiler that is supposed to check for exhaustiveness. Which is way worse if the catch-all arm isn't a `panic("Unhandled match branch!")`. Yes, you can counter that with GADT…

You don't have to add a catch-all arm, you can still explicitly match i.e

    match value {
      A => { do_stuff() },
      B => { unreachable!("B is not applicable here because ") },
    }
now when you add C you still have to match it(given the enum is exhaustive).

Re: Enums in Go

#32

Earlier quoted context omitted.

In theory yes. But practically there are always locations where we can't match every case, so we either have to live with a warning or add a catch-all arm. And as soon as a catch-all arm exists, we are in "not checked any more" state, but with a compiler that is supposed to check for exhaustiveness. Which is way worse if the catch-all arm isn't a `panic("Unhandled match branch!")`. Yes, you can counter that with GADT…

As long as the set is limited (as enums usually are), you can always go with the middle ground between omitted case and catch all: case FILE_NOT_FOUND: /* This is normal, nothing to do. */ break; This should still catch adding new value into the enum and not handling it.

I should have added that this solution stops working as soon as you're handling 5 out of 50 cases. Lexical tokens are which always trigger the mentioned problems in my code - often you match against subsets, are there are _way_ too many of them to add them all explicitly.

Re: Enums in Go

#33
post #31

Earlier quoted context omitted.

In theory yes. But practically there are always locations where we can't match every case, so we either have to live with a warning or add a catch-all arm. And as soon as a catch-all arm exists, we are in "not checked any more" state, but with a compiler that is supposed to check for exhaustiveness. Which is way worse if the catch-all arm isn't a `panic("Unhandled match branch!")`. Yes, you can counter that with GADT…

You don't have to add a catch-all arm, you can still explicitly match i.e match value { A => { do_stuff() }, B => { unreachable!("B is not applicable here because ") }, } now when you add C you still have to match it(given the enum is exhaustive).

Yes, I see, I should have mentioned that.

Same as above: this solution stops working as soon as you're handling 5 out of 50 cases (or, more realistically, 10 out of 200). Lexical tokens are which always trigger the mentioned problems in my code - often you match against subsets, as there are _way_ too many of them to add them all explicitly.

Re: Enums in Go

#34
post #24
post #8

I'm implementing a somewhat complex software in both Go and Rust. The Rust version is bith shorter and more readable - and probably more efficient - thanks to Rust enums and Rust error handling. I don't understand why golang doesn't copy Rust here. The error handling in particular could be a very simple change. I am not a huge fan of go:generate and similar projects. They add a level of unknown that goes against the…

go:generate is mostly just a marketing failure. If they'd called it 'procedural macros', everyone here would think it was the bee's knees.

To be honest, I'm not a huge fan of Rust's #derive() magic either.

Re: Enums in Go

#35
post #8

I'm implementing a somewhat complex software in both Go and Rust. The Rust version is bith shorter and more readable - and probably more efficient - thanks to Rust enums and Rust error handling. I don't understand why golang doesn't copy Rust here. The error handling in particular could be a very simple change. I am not a huge fan of go:generate and similar projects. They add a level of unknown that goes against the…

> I am not a huge fan of go:generate and similar projects. They add a level of unknown that goes against the core Golang design values. I'm not sure I would agree with that. go:generate is a core part of Go since v1.4 and the enum generators are the kind of thing that was intended. https://go.dev/blog/generate That said, enums would be a welcome improvement to the language. But even then, I think go:generate has a pl…

"add(ing) a level of unknown" is a very fair description from a code comprehensibility standpoint, since the go:generate directive is about running arbitrary executables.

Re: Enums in Go

#36
post #23
post #18

The problem isn't so much the lack of enums, it's more that there is no way to do exhaustive pattern matching at compile time. I have seen production systems go down because someone added a variant to an 'enum' but failed to handle that new variant everywhere.

There are two linters that add those checks: https://github.com/nishanths/exhaustive for values and https://github.com/alecthomas/go-check-sumtype for types. Both are integrated into golangci-lint. I use both a lot and have only a positive experience. Having support from the language would be nice, though.

Yeah, it makes a huge difference whether this is the default, and that's not a Go thing, it's not a programming language thing, it's the whole of human existence.

Literacy is an example. We're used to a world where it's just normal that other humans can make marks and interpret our own marks as to meaning. A thousand years ago that would be uncommon, ten thousand years ago vanishingly rare.

I really celebrate tools which take an idea that everybody agrees is a good idea, and bake it in so that everybody just has that, rather than agreeing it's a good idea but, eh, I have other things to do right now.

And it annoys me when I see these good ideas but they're left as an option, quietly for a few people to say "Oh, that's good to see" and everybody else misses out, as if "Literacy" was an optional high school class most of your peers didn't take and now they can't fucking read or write.

Example: Git has a force push feature, necessarily we can (if we have rights) overwrite a completely unrelated branch state, given any state X, now the state is our state Y instead. This isn't the default, that part is fine... Git also has "force-with-lease". This is a much better feature. Force-with-lease says "I know the current state of this branch is X, but I want to overwrite it anyway". If we're wrong, and X is not (any longer perhaps) the current state, the push fails. But force-with-lease isn't the default.

[Edited to fix clumsy wording in the last sentence]

Re: Enums in Go

#37
post #35

Earlier quoted context omitted.

> I am not a huge fan of go:generate and similar projects. They add a level of unknown that goes against the core Golang design values. I'm not sure I would agree with that. go:generate is a core part of Go since v1.4 and the enum generators are the kind of thing that was intended. https://go.dev/blog/generate That said, enums would be a welcome improvement to the language. But even then, I think go:generate has a pl…

"add(ing) a level of unknown" is a very fair description from a code comprehensibility standpoint, since the go:generate directive is about running arbitrary executables.

True.

Re: Enums in Go

#38

I’ve found the enumer [0] library does the job of generating usable helpers without too much pain or any obvious downsides. The ability to generate JSON [un]marshallers is particularly handy. Still, the lack of enums and enum/sum types remains by far my biggest gripe about Go. [0] https://github.com/dmarkham/enumer

[deleted]

Re: Enums in Go

#39
post #26
post #22

Earlier quoted context omitted.

Isn’t that the first thing you would do if you add a new variant?

Only if you remember, which you, or someone else, is bound to not eventually

added that every switch/if should handle this exhaustively. For any project with more than a few dozens of files, it is basically impossible to remember all the downstream code that uses the enum -- you have to track it down, or better, let compiler automate check all usages

Re: Enums in Go

#40

Use a slice of strings? type Color int const ( Red Color = iota Green Blue ) var Colors = []string{ "Red", "Green", "Blue" } Now (Colors[Red] == "Red") and (slices.Index(Colors, "Green") == Green).

If you add an enum entry but forget to update the slice, BOOM

And that's exactly the kind of thing people are discussing here.

Post reply on HN