4 ms·
It is precisely a sum type, no? https://go.dev/play/p/xlRegSDYytg https://go.dev/play/p/xlRegSDYytg As defined, the set of the type Ordered is exactly the sum
by BlackFly 2y ago
It is precisely a sum type, no? https://go.dev/play/p/xlRegSDYytg https://go.dev/play/p/xlRegSDYytg
As defined, the set of the type Ordered is exactly the sum of all elements of int, uint and string. The intersection of int and string would be empty. The or symbol makes sense because an element of Ordered is either a uint or an int or a string. An element of Ordered is not a uint and an int and a string.
It feels to me that static typed languages tend to give you intersection bounds and not union bounds. Rust has intersections, java has intersections. Meanwhile, if you have duck typing then you end up with a bunch of union types (see python -> mypy, javascript -> typescript). There are of course the general union types (not generic bounds) in C/C++/rust which kind of behaves in a similar fashion.
- jerf 2y agoNo, you have created "a type that can be one of int, uint, or string, or anything that backs directly to them". They all can >, and since that's the only thing you used in Max, everything works fine. You don't have a sum type; you have "a type that is either an int, a uint, a string, or something that backs to them", specifically. It doesn't come in as any sort of sum type, it is specifically one of those types directly. For one thing, as you've specified it, you don't even have a closed set of types. Off in another package I can declare a "type MyInt int" and use your Max on it, so if you tried to type switch in your Max function, you would not know about my type, and it is arguably the defining characteristic of a sum type that you can know all the branches it has. You can fix that by knocking off the tilde, but then you still have the problem that it is not legal to use "switch val := a.(type)", which is basically the level of deconstruction of a type that Go permits, because when the Max function is running, it is not running on a value of type "Ordered"; it literally has a value of the type you passed in. That's the whole point of generics, to have values of the concrete type that was passed in, and not a sort of "sum type". https://go.dev/play/p/MGhRjwvpdTh https://go.dev/play/p/MGhRjwvpdTh Note you don't get "Ordered". You get the specific types. That's not any sort of "generic weirdness", that's the real situation. That's why you can only use the intersection of operations they all support. If you want a sum type in Go, use closed interfaces: https://github.com/BurntSushi/go-sumtype https://github.com/BurntSushi/go-sumtype If you're willing to accept what you've written as a sum type, you should be even more willing to accept this method, which actually produces a reasonable approximation of one.
- Groxx 2y agoI broadly agree with you, so this isn't to disprove you or anything, but in case you hadn't seen it before: you can do type checks inside generic functions. You just have to trick the compiler / do pointless boxing because the compiler is overly simple. This fails: https://go.dev/play/p/3J4urjOU6lc https://go.dev/play/p/3J4urjOU6lc v, ok := thing.(target) But this works: https://go.dev/play/p/Zb_fnAMaqZb https://go.dev/play/p/Zb_fnAMaqZb v, ok := ((any)(thing)).(target) It's basically because generics are generated code for specific types with little more than text replacement, and type assertion only works on interfaces, and it can't rule out non-interfaces. But if you box it in an `any`, it's fine, just like it's fine to `((any)(5)).(int)` anywhere else (or any other equivalent construct).