5 ms·
FWIW, there's a slightly more concise way of expressing this in Go: type state int const ( on state = iota off )
by nmyk 6y ago
FWIW, there's a slightly more concise way of expressing this in Go:
type state int
const (
on state = iota
off
)
- josephcsible 6y agoI don't think the concern was verbosity so much as lack of type safety.
- nmyk 6y agoFair enough. I would say if the way someone uses the Go "enum pattern" is causing them to have issues with type safety then their code could probably use a refactor, but the point does stand.
- josephcsible 6y agoHow is it possible to use the Go "enum pattern" without having issues with type safety? It's inherently not type-safe at all.
- nmyk 6y agoBy "issues" I mean software defects.
- asdkhadsj 6y agoAfter using Go for ~5 years, so many little things in Rust blew me away. I thought I was okay with Go's "enums" but then I saw Rust's Enums. Most notably, the real enum type combined with pattern matching was an eye opener over what I've been missing. Iterators were another one. The ability to express data transformation (mapps/filters/etc) in a very concise way blew me away. I had no idea what I had gotten used to in Go, though that's definitely not to say that I didn't feel the pain. There's advanced features in Rust I could live without, but most of it just feels empowering. The beauty in it though, in my mind, is that you don't need to use all that advanced stuff. You can write Rust shockingly similar to Go. The only thing Go truly nailed in my eyes is green threads. Those will always be better in Go than Rust (though futures are getting way better). Go nailed green threads. But all the other "lack of features as a feature" left me frequently wanting for more tools to solve simple problems. And I was a Go nut. I have a Gopher plushie in my car for Petes sake.
- shpongled 6y agoThe crazy thing is that sum types (Rust enums) and pattern matching have been around for at least 30 years. I'm simply not interested in learning any new language that doesn't have sum types, they allow you to write incredibly expressive and terse code.
- estebank 6y agoFor all the complaints about the breakneck change in rust, it's a very "boring" language: all of its features with the single exception of the borrow checker already exist in other languages.
- anticonformist 6y agoIt's not any particular feature that makes a language a mess. It's the interaction between the features. It's a bit like mixing paint, it's very easy to end up with greyish poop. Go was designed by very experienced programmers that understood the cost of abstraction and complexity well. They didn't do an absolutely perfect job. It's probably true that Go would be a better language with a simplified generics implementation, enums, and maybe a bit more. That they erred on the side of simplicity shows how they were thinking. It's an excellent example of less is more. Most programmers never gain the wisdom and/or confidence to keep things boringly simple. Everyone likes to use cool flashy things because it makes what can be a boring job more interesting. But if your goal is productivity, and the fun comes from what you accomplish, then the code can be relatively mundane and still be very fun to write.
- estebank 6y agoGiven that I am involved in the Rust project I'm very likely biased, but given that I've focused on the learnability of the language (diagnostics and ergonomics) I have a bit of context on this subject. When designing a language there are intrinsic (what things the project wants to focus on, be they features of the language or the associated tooling that affect the language, like generics or compilation speed) and extrinsic (external impositions like being able to run on certain platforms, or interfacing with existing technologies like being able to run a statically linked binary in Linux or being able to debug using gdb or calling C libs without runtime translation) design constraints. All languages have (or should have) an objective of being easy to learn, pick up and use long term. It might just not be the top priority. For the sake of argument you can take Python where expressiveness at runtime and clean syntax are prioritized over speed, Go where fast compilation and multithreaded microservices are prioritized over more complex language features, and Rust where fast binaries and expressiveness are prioritized over ergonomics (when push comes to shove this is the case, otherwise you wouldn't need to call `.clone()` or add `&` to arguments when calling a method ever), you can see how these objectives permeate every decision throughout the language. When it comes to Rust in particular, I feel it is still a boring language despite the appearance of too many features, precisely because of how they interact between them and fit together naturally. It is not the best fit for every use case, but it is one of the projects out there that is embracing the fact that it can't be as easy to learn as it could be (without sacrificing some of the constraints that make it interesting as a systems language), but we can rely on the compiler being a necessary part of the developer toolchain to make the compiler understand the user's intent when they do things that make sense from extrapolated misunderstanding of the language and help them write the "correct" code instead. This has the added benefit that reading the code is easier because you have to "guess" much less what it is doing. Remember that if the code can confuse a parser it will also confuse humans. On the opposite end of the spectrum you have JavaScript, where it's grammar has a lot of optional or redundant ways of doing the same thing (think semicolon insertion), which makes the act of reading and debugging code harder. This is a reasonable approach in a case like the web, less so in a compiled language that can evolve independently from the end users' platform.
- coder543 6y agoIt is type safe. Any integers with a defined type cannot be used as values of type "state" without an explicit conversion occurring. Type safety does not guarantee exhaustive matching, unfortunately, because the underlying type is still an integer, but that's a separate issue. https://play.golang.org/p/K0m4hfmw8C1 https://play.golang.org/p/K0m4hfmw8C1 I wish Go had proper, exhaustive enums too (sum types preferably), but you're incorrect when you say that they don't have type safety.
- josephcsible 6y ago> also will compile, because integer literals are untyped until they are used Doesn't that make them type-unsafe? In C++ or Haskell, implicitly assigning integer literals like that isn't valid.
- coder543 6y ago> Doesn't that make them type-unsafe? No, it doesn't. Go's enums are type safe. You can't accidentally mix two different kinds of enum values, or accidentally use some random value of type "int" where an enum value is expected. The type system protects you from values of the wrong type being used. This was demonstrated by that Go Playground link. Literals in Go are untyped until they're used. How they're used determines the type, and then they have a very real type, with very real type safety being enforced. So, if you're using a literal "3" where an integer of type "state" is expected, the Go language specifies that the type of "3" is "state". This is an ergonomic issue when you're expecting exhaustive Sum Types, but not a type safety issue. Should all literal integers just always be a specific type? Let's decide that all literals should be of type "int". Great. Now you can't type a large, 64-bit integer literal to pass as a value to a function, because that would overflow the "int" type, even though the argument is desired to be "int64". There are trade-offs to every approach. > In C++ or Haskell, implicitly assigning integer literals like that isn't valid. I can't comment on how Haskell does things, but C++ is more complicated than you seem to think. https://en.cppreference.com/w/cpp/language/integer_literal#The_type_of_the_literal https://en.cppreference.com/w/cpp/language/integer_literal#T... "The type of the integer literal is the first type in which the value can fit, from the list of types which depends on which numeric base and which integer-suffix was used." Go's approach is equally type safe here. It assigns the type to the literal based on the expression the literal is used in. As I said before: I really wish Go had proper Sum Types. But enums in Go are type safe, contrary to what you have claimed in several comments here.
- tsimionescu 6y ago`iota` is one of the strangest features in Go by far for me. So much complexity for such a simple feature with so few applications, instead of implementing even simple enums...