Live data from Hacker News

Sum Types in Julia and Rust

andreaskroepelin.de

11–20 of 70 posts

Re: Sum Types in Julia and Rust

#11
post #8

When I think of sum types, I like the categorical definition the best, which is that a sum A+B has two morphisms (i.e. constructors) Inl : A -> A+B and Inr : B -> A+B, with a simple commuting diagram[0]. Or in Rust, enum Sum { Inl(A), Inr(B), } Why do I prefer this definition? Well, category theory abstracts away irrelevant details, and sums have a "universal property" associated with them. Roughly speaking that mean…

I don't know any category theory whatsoever. What happens in your example if A = B? Would it have two morphisms or just one?

Re: Sum Types in Julia and Rust

#12
post #3

I may be wrong, but I don't think this is what people mean by 'sum types'. I was expecting union types (e.g., https://www.typescriptlang.org/docs/handbook/unions-and-inte... or https://dotty.epfl.ch/docs/reference/new-types/union-types.h... ) I guess enums are a type of sum type, but seems this is more specifically about enums

Simple way to think about it is plus. Sum plus sum increases, union plus union does nothing. 1. A union type is like int | double. It means the value is one of a set of possible types. And it's a true set: `int | int | double` is indistinguishable from `int | double`. 2. A sum type is a new type built from a list of other types, which assigns a 'tag' to each possible list element, like a Rust enum. The tags are not t…

Thanks! This clarifies the situation

Re: Sum Types in Julia and Rust

#13
post #8

When I think of sum types, I like the categorical definition the best, which is that a sum A+B has two morphisms (i.e. constructors) Inl : A -> A+B and Inr : B -> A+B, with a simple commuting diagram[0]. Or in Rust, enum Sum { Inl(A), Inr(B), } Why do I prefer this definition? Well, category theory abstracts away irrelevant details, and sums have a "universal property" associated with them. Roughly speaking that mean…

I don't know any category theory whatsoever. What happens in your example if A = B? Would it have two morphisms or just one?

There'll still be two morphisms, Inl : A -> A + A and Inr : A -> A + A

Re: Sum Types in Julia and Rust

#15
post #8

When I think of sum types, I like the categorical definition the best, which is that a sum A+B has two morphisms (i.e. constructors) Inl : A -> A+B and Inr : B -> A+B, with a simple commuting diagram[0]. Or in Rust, enum Sum { Inl(A), Inr(B), } Why do I prefer this definition? Well, category theory abstracts away irrelevant details, and sums have a "universal property" associated with them. Roughly speaking that mean…

I don't know any category theory whatsoever. What happens in your example if A = B? Would it have two morphisms or just one?

What might be causing confusion is the difference between tagged unions and untagged unions.

A union type "A | B" means "a value of type A or a value of type B". Example:

    function f1(): String | Integer {
        if (rand()) {
            return "hello"
        } else {
            return 12
        }
    }

    function f2(x: String | Integer) {
        switch (typeof x) {
            case String: return "string: " + x
            case Integer: return "integer: " + x
        }
    }
The type "String | String" is exactly equivalent to "String".

A tagged union (aka sum type) "A + B" means "either a left value or a right value; if it's the left, it has type A, if it's the right it has type B".

    function g1(): String + Integer {
        if (rand()) {
            return Inl("hello")
        } else {
            return Inr("bye")
        }
    }

    function g2(x: String + String) {
        switch (x) {
            case Inl(s): return "left value: " + x
            case Inr(s): return "right value: " + x
        }
    }
The type "String + String" has one bit of additional information than just "String".

Re: Sum Types in Julia and Rust

#16
Two thoughts:

For this problem, I would use union types in Julia. Union types are a sort of sum, but they are amalgamated sums whilst sums types in PL semantics usually means disjoint sums. The difference is that disjoint sums 'mark' whether a value is of the left or right type, while with amalgamated sums the value may belong unmarked to the intersection. The distinction does not matter in the example the post gives.

Second, Julia does not give the benefit that Rust gives of type coverage, that is, ensuring that functions that take the sum type as argument actually are defined for each branch of the sum type. The Rust compiler guarantees this automatically. AFAICS, with Julia it is up to the user to provide tests exploring the branches.

Re: Sum Types in Julia and Rust

#17
post #16

Two thoughts: For this problem, I would use union types in Julia. Union types are a sort of sum, but they are amalgamated sums whilst sums types in PL semantics usually means disjoint sums. The difference is that disjoint sums 'mark' whether a value is of the left or right type, while with amalgamated sums the value may belong unmarked to the intersection. The distinction does not matter in the example the post gives…

Julia is a dynamic language, I don't think having the rigor of a compiled language (probably the most rigorous out there) is a reasonable expectation. It would be nice to have as an external linter service, probably.

Re: Sum Types in Julia and Rust

#18
Julia enums do not equal to Rust enums. You can achieve that functionality (that a type can be one of a set of cases, type algebra in general) with subtypes. Which is fine I'd say, but there could be terser syntax for it (which is available through packages, and it's slower). Having abstract types which cannot be instantiated is also nice.

Re: Sum Types in Julia and Rust

#19
post #6
post #3

I may be wrong, but I don't think this is what people mean by 'sum types'. I was expecting union types (e.g., https://www.typescriptlang.org/docs/handbook/unions-and-inte... or https://dotty.epfl.ch/docs/reference/new-types/union-types.h... ) I guess enums are a type of sum type, but seems this is more specifically about enums

I believe another word for enums (in the Rust sense, not in the C++ or Java sense) are tagged unions.

That's right. It's unfortunate that Rust calls them "enums", since as you noted that term already had a well-established meaning in other languages, and the concept that Rust calls "enums" also had several existing names (sum type, coproduct type, disjoint union, and, more generally, algebraic data type) in the literature and in prior languages.

Language designers: stop changing the meanings of words! I know you mean well and you're trying to tie unfamiliar ideas to familiar ones for beginners, but you end up causing more confusion for everyone in the long run.

Re: Sum Types in Julia and Rust

#20
post #3

I may be wrong, but I don't think this is what people mean by 'sum types'. I was expecting union types (e.g., https://www.typescriptlang.org/docs/handbook/unions-and-inte... or https://dotty.epfl.ch/docs/reference/new-types/union-types.h... ) I guess enums are a type of sum type, but seems this is more specifically about enums

Rust enums are full union types. i.e. while each possibility in a (say) Java enum must be of the same type, each possibility in a Rust enum can be of a different type. i.e. https://play.rust-lang.org/?version=stable&mode=debug&editio...

However, Rust's enum-type members are still named - to my knowledge you can't have anonymous enum type members in Rust.

In the example you gave, the type-of `left` is still `SumType::Left` instead of being just `String`.

I'm not too familiar with Rust to say, but I don't consider this to be a syntactically zero-cost abstraction (even if the wrapper-types are elided by the compiler) because we still have more keyboard typing to do than we should be doing, imo.

Post reply on HN