6 ms·
Zig is a modern imperative programming language with ADTs: https://ziglang.org/documentation/master/#Tagged-union https://ziglang.org/documentation/master/#Tagg
by skywal_l 2y ago
Zig is a modern imperative programming language with ADTs: https://ziglang.org/documentation/master/#Tagged-union https://ziglang.org/documentation/master/#Tagged-union
- madeofpalk 2y agoAlso Typescript https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types https://www.typescriptlang.org/docs/handbook/2/everyday-type...
- fanf2 2y agoUnion types are not the same as sum types.
- dtech 2y agoTS narrows union types cases based on conditionals like "if" (called discriminated unions in the docs in the past), and supports exhaustiveness checks. How do they differ in functionality from sum types?
- mpawelski 2y agoSupports exhaustiveness checks only if you explicitly opt-in it (by coding to pattern where you use helper function that accepts `never` type). "Dicriminated Unions Type"/"Sum Types" feels very hacky there, at least syntax-wise, because it is constraint by being "JS + types" language. It's remarkable what Typescript can do, but having native Discriminated Unions in JS (hence in TS too) would be much more ergonomic and powerful.
- nyssos 2y agoSum types are disjoint unions. This `T` has three cases L = { tag: "a", payload: string } | { tag: "b", payload: number } R = { tag: "b", payload: number } | { tag: "c", payload: boolean } T = L | R whereas a proper sum type `L + R` would have four.
- brabel 2y agoIsn't that a completely useless distinction? For all purposes and intents, the "b" type in L and R should be treated the same, no? What do you gain by not doing that??
- hexane360 2y agoThis often comes up when writing a function which returns a wrapper over a generic type (like Option<T>). If your Option type is T | null, then there's no way to distinguish between a null returned by the function or a null that is part of T. As a concrete example, consider a map with a method get(key: K) -> Option<V>. How do you tell the difference between a missing key and a key which contains `null` as a value?
- brabel 2y agoThis is trivial to model by making your type `T | null | Missing`.
- efnx 2y agoMaybe trivial to “work around” but there is a difference, ay? With this type you would have to check/match an extra case! The type you use there also takes more memory than Option<T> or Maybe<T>. So it has some other downsides.
- epolanski 2y agoOr just using Option since you would have Some<null> or None in that case.
- hexane360 2y agoOnly if you're designing both functions ahead of time. In other words, it's not composable.
- epolanski 2y ago`T | null` is equivalent to T. You can assign null to `T`> It's like saying `string | "foo"` it is simply `string` due to subtyping.
- chem83 2y agoF# too. And Elm. But I get your point.
- chongli 2y agoWhile this is a step up from C, it is still a long way from the full power and generality of algebraic data types. The key word here is algebraic. In a language with ADTs, such as Haskell, you can pattern match on an arbitrarily complex types, not just the outermost tag. A contrived example (from [1]): contrived :: ([a], Char, (Int, Float), String, Bool) -> Bool contrived ([], 'b', (1, 2.0), "hi", True) = False To achieve a result like this using Zig's switch syntax would seem to involve a huge amount of boilerplate code and nested switch statements. [1] https://www.haskell.org/tutorial/patterns.html https://www.haskell.org/tutorial/patterns.html
- Hirrolot 2y agoThis is more of syntax sugar than power and generality, since nested pattern matching can be mechanically translated into "top-level" matching (e.g., see [1] and [2]). [1] L. Augustsson. Compiling Pattern Matching. In Functional Programming Languages and Computer Architecture, pages 368– 381, 1985. [2] P. Wadler. Efficient Compilation of Pattern Matching. In S.L. Peyton Jones, editor, The Implementation of Functional Programming Languages, pages 78–103. Prentice Hall, 1987.
- chongli 2y agoThis argument is the most common fallacy I see in programming language discussions. I might as well give it a name right here: "Turing equivalence fallacy" or perhaps "syntax sugar fallacy." All Turing Complete programming languages are Turing equivalent to one another. Programs written in one language can be mechanically transformed into those written in another. This is irrelevant to the discussion of programming languages. The whole point of creating different programming languages is to explore different ways to express the same program!
- Hirrolot 2y agoIn programming language design, we tend to distinguish between global and local analysis. While type checking and elaboration is an example of global analysis, desugaring is inherently local to some piece of code. Therefore, "power" or "expressiveness" usually mean that something cannot be syntactically "expanded"; e.g., while type classes elaborate into explicit dictionaries, they still require information from the type checker, and therefore considered a "real" feature of a programming language. On the other hand, nested pattern matching can be formulated as local syntax transformation, and therefore it doesn't bring anything fundamentally new to the type system or dynamic semantics. There's also a great talk on the matter [1], if somebody is interested in formalities. [1] https://www.youtube.com/watch?v=43XaZEn2aLc https://www.youtube.com/watch?v=43XaZEn2aLc