3 ms·
> Enumerations I don't see the value in defining a custom underlying type for an enum. If it's for efficiency, sure. I've never had to use enums in a heavily
by shhsshs 7y ago
> Enumerations
I don't see the value in defining a custom underlying type for an enum. If it's for efficiency, sure. I've never had to use enums in a heavily performance-sensitive context so I don't personally relate to that.
> The assert also leaves an opening for a runtime error which is unacceptable.
You can handle errors gracefully.
// default to 0
maybeInt, _ := myValue.(int)
maybeInt, ok := myValue.(int)
if !ok {
// do something else
}
> imagine syntax like this:
In my opinion JSON with multiple types like that is poor design.
Regardless, even with sum types the programmer has to write code for most possible states each value could be in. You have the same capability in Go with type assertions.
// Rust
match myValue {
int => ...,
string => ...,
// etc.
}
// Go
switch myValue.(type) {
case int:
...
case string:
...
// etc.
}
- crimsonalucard 7y agoThis isn’t about personal opinion. This is about understanding the fundamental mathematics behind types. In type theory there are two fundamental composite types. Product types and sum types. Sum types are types that can be A or B or C. Product types can be A and B and C. An example of a product type is any type that can hold multiple typed entities, whether that’s a list, array, structure or map. An example of a sum type is polymorphism defined using inheritance. The children of a parent type are encoded into the type itself, but the type instantiated can only take the form of one of the children. Note that my example for the sum type is isomorphic to a typed enum. It’s literally the same concept. Sum types and product types are mathematical opposites. Every language that has algebraic data types has this concept encoded into it. Go is one of the few typed languages that doesn’t have it. Let’s get away from the mathematics and talk about practicality. Your example of the switch and pattern matching. Let’s say myValue is an int, a string or a float. Let’s also say that when you are coding you miss checking for the float case and you add an extra invalid case where the code checks for Double? What happens in rust or go? In go nothing happens because go doesn’t truly know the underlying type so by doing this the code compiles and you have encoded a runtime error into the code. For rust exhaustive type checking will catch both the missing handler and the invalid case. That’s right rust will know you have missing logic based off of the type. This is a powerful feature that is encoded into most languages that have algebraic data types. Now let’s take the conversation back to math. The fundamentals. Have you ever thought about what an Int actually is? Looks like an enum doesn’t it? type int = 0 | 1 | 2 | 3 ... If you really want to get deep an int is actually a recursive enumeration similar to json. type int = 0 | (int, 1) | (int, 2) | (int, 3) | ... (int, 9); So for example ints are instantiated like this.. 0 = 0, 1 = (0, 1) 2 = (0, 2) . . . 12 = ((0, 1) 2) . . . 456 = (((0, 4), 5), 6) Operations like addition and multiplication are defined in terms of inductive mappings between enumerations. This fundamentally what a type is. Any language missing the ability to define this is missing a mathematical primitive. It is incomplete. Go is a language that simply has an arbitrary enumeration (int) defined and the rest of the code needs to build off of it as there is no mechanism to define your own. Ints should be encoded as enumerations not the other way around.