upvote
This may be a bit too pedantic, but I consider interface {} to be a way to do polymorphism via type classes. Interface defines an open class of types which implement some interface.

Sum types are a type definition defining something as A or B. Not “anything that quacks like a duck”. But concretely “one of this or one of that”. This enables different syntax, like the match expression to be used, in which you exhaustively list all the variants. The compiler doesn’t need to heap allocate enums because it knows the maximum size of a single value. The compiler and programmer can take advantage of the knowledge that there’s a closed set of values the type can hold. It’s not an open type class.

Result and Option are quite beautiful as sum types. But they’re horrible as type classes. Try implementing them using interface{} in Go. It’s not the same.

reply
> Interface defines an open class of types

But can also define a closed set of types, perfectly satisfying "sum types".

> This enables different syntax, like the match expression to be used, in which you exhaustively list all the variants.

Go does not provide this out of the box, but that is not prerequisite for sum types. The mathematical theory says nothing about "the compiler must produce an error if the user doesn't match call cases". There is sufficient information provided by the sum types if you wish to add this to your build chain yourself, of course.

reply
By that definition a void* pointer in C is a sum type. By that definition assembly has sum types.

This argument feels like the “we have sum types at home” meme. Ergonomics matter.

I write a lot of rust. Rust has traits which are similar to Go’s interfaces. But the features aren’t the same, and I use enum all the time. (I also use trait all the time, but I use trait and enum for different things).

reply
> By that definition a void* pointer in C is a sum type.

No. That doesn't make any sense. void* is essentially equivalent to any in Go, which isn't sum types either.

You can construct sum types in C by combining structs, enums, and unions, but it is not an out of the box feature like in Go. Sum types are a first-class citizen in Go.

> Ergonomics matter.

Math doesn't care about ergonomics. You might care about ergonomics, but logically when talking about those ergonomics you'd call those ergonomics by name, not by some unrelated thing from type theory.

reply
> You can construct sum types in C by combining structs and unions, but it is not an out of the box feature like in Go. Sum types are a first-class citizen in Go.

Maybe I'm misunderstanding what you mean. Can you give me an example? How would you write a Result type in Go? (Result is defined as either Ok(val) or Err(err))

reply
C:

    enum result_type {
        OK,
        ERROR
    };

    union result_value {    
        int value;
        char *error_message;
    };

    struct result {
        enum result_type tag;
        union result_value value;
    };
This is not technically closed, but does offer a close enough approximation. Again, not a first-class feature, so there is no expectation if it being true sum types.

Go:

    type Result interface {
        isResult()
    }

    type OK[T any] struct {
        Value T
    }
    func (OK[T]) isResult() {}

    type Error struct {
        Message string
    }
    func (Error) isResult() {}
This one is closed. It perfectly satisfies being sum types. It may not satisfy your opinion of what makes for good ergonomics, but if you want to talk about ergonomics let's use ergonomic words, not type theory words.
reply
I'm curious, if tagged unions are a subset of sum type, what is your definition of "sum type"?

AFAIK, tagged union is sum type, based on sum type mathematical definition.

reply
On second thought, I agree with your definition. So Go does, in fact, have tagged unions.
reply