Hacker News new | past | comments | ask | show | jobs | submit login

Adding ADTs on their own is not enough, you need to add pattern matching and generics to unlock their biggest benefits.



Go's type switches could be good enough if there was a way to restrict an interface-like type to be either one of A, B, C types.

    type foo either {
     int
     string
     *bar
      baz
    }
...

     var f foo = ....
     switch v := f.(type) {
       case int:
       // v has type int
       case string:
.....


The problem with this is it's extremely limiting and conflicts with interfaces. So it's not very useful: you can't define enumerations with no associated data, or enumerations with the same associated data types, without the syntactic overhead of explicitly wrapping and unwrapping those types. So you'd end up with

    type thing1 int
    type thing2 int
    type foo either {
        thing1
        thing2
    }

    var f foo = …
    switch v := f.(type) {
        case thing1:
            data = int(v)
        case thing2:
            data = int(v)
        …
and frankly that's a bit gross.

I think `select` would be a better basis for dispatching than switch as it already supports getting data out of stuff, and it better represents the linear top-to-bottom dispatching.


I'm a bit confused about the example. It seems you care about tagging an integer with a qualifier.

    type foo struct (
      kind Kind
      data int
    }
Then you switch on kind and you use the data

The type switch is useful when you have to consume the actual type, without runtime errors for type conversions


> I'm a bit confused about the example. It seems you care about tagging an integer with a qualifier.

No, I'm pointing out that a proper sum type can (and often does) need that. It doesn't mean those are the only members.

> The type switch is useful when you have to consume the actual type, without runtime errors for type conversions

My point is that the type switch is garbage when multiple variants can have the same associated type.


I see; that's because I'm this case we'd be fusing the discriminator with the payload.

With destructuring pattern match constructs you'd be binding variables to "inner" members of the sum type.

I do understand that. I'm not so sure it's so important, compared to Just being able to say that a box can contain either A or B or C.

Interfaces are great when you don't care what does a box contain as long as it quacks like a duck.

Sometimes though you need to carry around one out of N types of something and currently all you can do is to use an interface{} and deal with the possibility of a runtime error if somebody breaks the invariant.


> I do understand that. I'm not so sure it's so important

It absolutely is, even more so because of Go's interface. The difficulty of properly discriminating between interfaces extending one another is a reason the FAQ gives for rejecting union types.

> compared to Just being able to say that a box can contain either A or B or C.

I'd argue that this is by far the lesser use case, and furthermore trivially and completely subsumed by the alternative.

> Sometimes though you need to carry around one out of N types of something and currently all you can do is to use an interface{} and deal with the possibility of a runtime error if somebody breaks the invariant.

And sometimes you need to carry around one of N values some of which have overlapping contents and currently all you can do is get bent.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: