4 ms·
> Enumerations - those are integers not enumerations. In Golang they have a type Bool which is either true or false. Can I define my own type using the same co
by crimsonalucard 7y ago
> Enumerations
- those are integers not enumerations.
In Golang they have a type Bool which is either true or false.
Can I define my own type using the same convention in GoLang? No. I can't. Ideally I want the ability to do this:
type Bool = Enum {
True
False
}
or
type Tri = Enum {
True
False
QuantumTrueFalseDuality
}
But in Golang I'm locked in with what the creators provided as primitive types. I can't go deeper. Rust you can.
> Sum types.
I don't think you know what a sum type is. This is what I mean by lack of knowledge. For sum type (A | B), A and B do not need to have a single thing in common and they do not need to share an interface. Think of a product type (A, B) as A and B and a sum type (A | B) as A or B.
The most glaring replacement of sum types in go are done with product types that contain errors from IO functions in GoLang. The Error type does not have anything in common with the Value it usually shadows and therefore both cannot be represented with an interface.
> Recursive types.
That's somewhat recursive. But that's a pointer. This works and is valid. Ideally though it shouldn't be a pointer but for efficiency during memory allocation this is a viable restriction. Recursive types only with pointer types.
> Parametric Polymorphism
I agree with you.
> Is this not acceptable?
No it is not acceptable. Interface is unusable until you make the type concrete with your asserts. Asserts are you executing a guess on a possible JSON permutation. In your second example you are guessing the type to be an array of INTs. What if that string was arriving over the wire as IO and you don't know what configuration it will be in? What if the typing was more complicated?
jsonString = "[1,2,True,[1,2,\"hello\"]]"
or
jsonString = randomJSONFromIO()
The assert also leaves an opening for a runtime error which is unacceptable.
imagine syntax like this:
type JSON :: []JSON | Struct{string: JSON} | bool | int | string | null
var x JSON = json.Unmarshal("[[1,2,True,[1,2,\"hello\"]],{}, null]")
JSON is a type represented using sums (|), products (Struct) and recursion (JSON). There is no possibility of run time errors here as you don't need to guess a specific permutation of JSON. You don't need to guess because such a type system can fully represent JSON. You see what is missing with go?
- HeyImAlex 7y agoIsn’t that JSON example the same in python, javascript, and ruby? Unmarshalling into an interface is really just a shitty enum; the number of permutations is finite. A type switch here is like a match but less type safe because it won’t check exhaustiveness of the branches.
- crimsonalucard 7y ago>Isn’t that JSON example the same in python, javascript, and ruby? No. Python doesn't have type checking. That example is a made up syntax of golang if golang had all the correct type primitives. In this example I am defining a type in the first line, similar to how you would define a struct in golang. Then using the type in the second line. There is a bit of an error, but it's too late to edit it now. the Struct in the type line should be map[string]JSON. >Unmarshalling into an interface is really just a shitty enum; the number of permutations is finite. The permutations of JSON are infinite. In the real world there are APIs describing deeply hierarchical data that have unpredictable deeply nested data structures. If I had a random JSON string generator, it's not that straightforward how you would save that JSON to a correctly typed variable in a GO program. Unmarshalling you will have to define a new type for every permutation. It makes more sense to traverse the data structure to find it's structure rather then take a wild guess. Either way in golang that "guess" happens at runtime so it will spit out an error at runtime, while with sum types and match you are type safe before the program even runs.
- HeyImAlex 7y agoI mean... that’s the point I was making. Interface is just like using a dynamically typed language. So saying python can do this but golang can’t is wrong. They are effectively the same. RE: Permutation, the unmarshalled value will only ever be float64, bool, string, interface[], or map[string]interface. The nested interfaces are recursively defined. It’s literally just like doing it in rust, except the compiler won’t do exhaustiveness checks for you.
- crimsonalucard 7y agoHm. Ur right bad examples. The only advantage rust has then is more elegant syntax and safety for JSON. Ur also right about python and ruby. It is effectively the same. Overall though the need for assert is a sign of a crippled type system.
- speedplane 7y ago
- dullgiulio 7y agoThose above are not integers but type that you have to explicitly cast integers to if you really want. Please don't make uninformed comments.
- crimsonalucard 7y agoI don’t understand what you are referring too. Why don’t you clarify, then we’ll see who is truly uninformed. I readily cop to my mistakes and errors. Will you?
- 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.