# \[ANN\] SumTypes.jl 0.1

**URL:** <https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161>\
**Category:** Package Announcements\
**Created:** [September 23, 2020, 10:42pm UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161 "2020-09-23T22:42:25Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [September 23, 2020, 10:42pm UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/1 "2020-09-23T22:42:25Z")

</div>

Hi everyone, I’ve been playing around a bit lately with the idea of ‘sum types’ (aka tagged unions, or enums in Rust circles). These are quite the hotness these days in functional programming and I kept having trouble fully getting my head around them, so I finally just sat down and implemented them in julia, which has clarified things for me a fair amount.

Check it out at [SumTypes.jl](https://github.com/MasonProtter/SumTypes.jl).

I think at least in a dynamic language like Julia, there’s good reason to be skeptical of any claim that these are an alternative to `Union`, however I think maybe there are some uses for these things, and at the very least if someone tells you

> Julia is a terrible programming language, it doesn’t even have sum types, the greatest language feature ever!

you can just tell them

> Big deal, Mason made a sum type package in 55 lines of julia code.

* * *

If you really don’t wanna click on the link, here’s an excerpt from the README where I explain a bit about what a sum type is and how they work:

# SumTypes.jl

Sum types, sometimes called ‘tagged unions’ are the type system equivalent of the [disjoint union](https://en.wikipedia.org/wiki/Disjoint_union) operation (which is _not_ a union in the traditional sense). From a category theory perspective, sum types are interesting because they are _dual_ to `Tuple`s (whatever that means).

At the end of the day, a sum type is really just a fancy word for a container that can store data of a few different, pre-declared types and is labelled by how it was instantiated.

Users of statically typed programming languages often prefer Sum types to unions because it makes type checking easier. In a dynamic language like julia, the benefit of these objects is less obvious, but perhaps someone can find a fun use case.

Let’s explore a very fundamental sum type (fundamental in the sense that all other sum types may be derived from it):

```julia
julia> using SumTypes

julia> @sum_type Either{A, B} begin
           Left{A, B}(::A)
           Right{A, B}(::B)
       end

```

This says that we have a sum type `Either{A, B}`, and it can hold a value that is either of type `A` or of type `B`. `Either` has two ‘constructors’ which we have called `Left{A,B}` and `Right{A,B}`. These exist essentially as a way to have instances of `Either` carry a record of how they were constructed by being wrapped in dummy structs named `Left` or `Right`. Here we construct some instances of `Either`:

```julia
julia> Left{Int, Int}(1)
Either{Int64,Int64}(Left{Int64,Int64}(1))

julia> Right{Int, Float64}(1.0)
Either{Int64,Float64}(Right{Int64,Float64}(1.0))

```

Note that unlike `Union{A, B}`, `A <: Either{A,B}` is false, and  
`Either{A, A}` is distinct from `A`.

## Pattern matching on Sum types

Because of the structure of sum types, they lend themselves naturally to things like pattern matching. As such, `SumTypes.jl` re-exports `MLStyle.@match` from [MLStyle.jl](https://github.com/thautwarm/MLStyle.jl/) and automatically declares Sum types as MLStyle record types so they can be destructured:

```julia
julia> @match Left{Int, Int}(1) begin
           Either(Left(x)) => x + 1
           Either(Right(x)) => x - 1
       end
2

julia> @match Right{Int, Int}(1) begin
           Either(Left(x)) => x + 1
           Either(Right(x)) => x - 1
       end
0

```

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [September 24, 2020, 2:06am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/2 "2020-09-24T02:06:36Z")

</div>

How is sum type different to `Union`? Also,

> [@Mason](#):
>
> Julia is a terrible programming language, it doesn’t even have sum types, the greatest language feature ever!

If we live by what others thinks, are our lives still ours?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [September 24, 2020, 2:21am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/3 "2020-09-24T02:21:14Z")

</div>

> [@xiaodai](#):
>
> How is sum type different to `Union` ?

> [@Mason](#):
>
> Note that unlike `Union{A, B}` , `A <: Either{A,B}` is false, and `Either{A, A}` is distinct from `A` .

> [@Mason](#):
>
> At the end of the day, a sum type is really just a fancy word for a container that can store data of a few different, pre-declared types and is labelled by how it was instantiated.

A sum type is just a container that holds values that can be picked from a union. e.g. for the `Either` example, the macro basically generates the code:

```julia
julia> struct Left{A, B}
           l::A
           Left{A, B}(x) where {A, B} = Either{A, B}(new{A,B}(x))
       end

julia> struct Right{A, B}
           r::B
           Right{A, B}(x) where {A, B} = Either{A, B}(new{A,B}(x))
       end

julia> struct Either{A, B}
           data::Union{Left{A,B}, Right{A,B}}
       end

```

Sum types are more restrictive and less expressive than unions and that’s why they’re helpful for static compilation, or cases where you want to be able to enumerate every possibility and not let people add cases in post-hoc.

`Either{A,B}` is kinda the prototypical sum type, and it’s the one that you’ll hear some static language enthusiasts say is “basically a union but better”, but fundamentally with union we have that `A <: Union{A, B}` and we have that `A === Union{A, A}`. Both of those (very useful!) properties don’t hold with sum types.

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [September 24, 2020, 2:22am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/4 "2020-09-24T02:22:35Z")

</div>

It’s like tha `Maybe` design heavily criticised by Rich Hickey. Julia’s union is superior. I wish there is a more convenience syntax though.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [September 24, 2020, 2:28am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/5 "2020-09-24T02:28:41Z")

</div>

Yes, this is exactly the sort of object Rich Hickey criticized in his [Maybe Not](https://www.youtube.com/watch?v=YR5WdGrpoug) talk.

> [@xiaodai](#):
>
> Julia’s union is superior.

That’s not a very meaningful statement unless you say what it’s superior for. I certainly like `Union`s, but there are cases where sum types are nice (like type checking).

An important thing to note here is that you can build sum types if you have unions, but you can’t build unions if all you have are sum types. In some circumstances, having a more restricted type system like the one you get with sum types can be useful.

Sum types are useful if what you desire is very strong coupling between different parts of your code, and unions / subtyping are useful if you want more flexible, loosely coupled ‘open’ code.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [September 24, 2020, 4:58pm UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/6 "2020-09-24T16:58:09Z")

</div>

If anyone is curious about seeing sum types in use, there was a nice blog post circulating a little while ago called [Optionality in the type systems of Julia and Rust](https://andreaskroepelin.de/blog/sum_types/) (originally titled Sum types in Julia and Rust).

In the blog post, the author considers building up a little game shows one way to solve their problem in Rust using sum types and pattern matching (called enums here), but then shows that julia’s enums are not up to the task.

A transcription of the Rust ‘enum’ code would look like this with SumTypes.jl:

```julia
using SumTypes

@sum_type PlayerClass begin
    Solarian(health::Base.RefValue{Int}) # using a Ref here lets us mutate the health of a Solarian
    Polarian(health::Base.RefValue{Int}) # in a real game there'd probably be more fields here
    Centaurian(health::Base.RefValue{Int})
end

struct GameState
    daytime::UInt
    player::PlayerClass
end

function homestar(p::PlayerClass)
    @match p.data begin
        ::Solarian => "sun"
        # ...
    end
end

function greet(self::PlayerClass, other::PlayerClass)
    @match (self.data, other.data) begin
        (::Centaurian, ::Polarian) => println("Hello, fellow three-star-systemer!")
        # ...
    end
end

function takedamage!(p::PlayerClass)
    @match p.data begin
        Solarian(health) => (health[] -= 42)
        # ...
    end
end

```

Now at the repl, let’s try and damage a Solarian:

```julia
julia> let p = Solarian(Ref(100))
           takedamage!(p)
           p
       end
PlayerClass(Solarian(Base.RefValue{Int64}(58)))

```

Tada!

Of course, the julia example using multiple dispatch is actually a fair deal nicer than this and can be extended with new player types quite easily later on if desired.

However, I think it’s nice to be able to show off that we can do this same business with sum types as well if we found the need.

---

<div class="post-metadata">

**Author:** ![kevbonham](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kevbonham/32/216165_2.png) [@kevbonham](https://discourse.julialang.org/u/kevbonham)\
**Post date:** [September 25, 2020, 12:51am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/7 "2020-09-25T00:51:15Z")

</div>

I don’t understand the point of this, and I doubt I will ever have cause to use it, but hot damn I love being part of a community where people build stuff like this just for the hell of it to learn, and make something that might be really useful for someone, sometime.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [September 25, 2020, 7:53am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/8 "2020-09-25T07:53:49Z")

</div>

> [@Mason](#):
>
> it’s nice to be able to show off that we can do this same business with sum types as well if we found the need

Sorry for being thick, but I still don’t get the motivation for sum types _in Julia_. I understand that they are useful in Rust, but idiomatic Julia code would simply do these things differently (subtyping or traits).

Programming languages are composed of various features that (ideally) fit together nicely. One cannot just pick one particular feature and expect to have something exactly like that in another language, or claim that some other language is less powerful because it doesn’t have X.

For example, I am sure that the Rust community would be surprised if someone claimed that their language is less powerful than C because it lacks undisciplined pointer manipulation. For them it is kind of the point.

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [September 25, 2020, 9:18am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/9 "2020-09-25T09:18:21Z")

</div>

> [@Tamas\_Papp](#):
>
> idiomatic Julia code would simply do these things differently (subtyping or traits)

That is a logical argument which seems to make sense. However, history is full of logical arguments that seemed to make sense at first, but ultimately turned out to be flawed.

The existence of a SumTypes package will provide empirical data, as it will either end up being used or not.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [September 25, 2020, 11:07am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/10 "2020-09-25T11:07:34Z")

</div>

I think you misunderstand. I am not arguing the package is not useful, just asking about the use case.

It seems an interesting idea, I just can’t figure out the motivation in the context of Julia. I think that asking about use cases in a package announcement is fair.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [September 25, 2020, 2:41pm UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/11 "2020-09-25T14:41:44Z")

</div>

> [@Tamas\_Papp](#):
>
> Sorry for being thick, but I still don’t get the motivation for sum types _in Julia_ . I understand that they are useful in Rust, but idiomatic Julia code would simply do these things differently (subtyping or traits).

My motivation was purely just coming from me wanting to wrap my head around the concept. I basically ended up making this because every time I hear about sum types, I didn’t feel like I fully ‘got’ them. I’m sure there’s things I’m missing, but I feel like there’s a lot of Rust and Haskell code I’ve looked at before that I now understand.

I don’t really think these things are very useful in current modern julia. One thing I will say though is that these things _may_ be useful in a hypothetical future where we have a statically compiled subset of the language, but that really wasn’t my motivation.

This was just tinkering on my behalf and I just wanted to share the thing I made with the community in case anyone learned anything from it or found it useful.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [September 26, 2020, 12:20am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/12 "2020-09-26T00:20:57Z")

</div>

People sometimes want a missing value of “type `Union{Missing,T}`” (which is of course impossible with the `missing` we have). Isn’t it a reasonable use-case? Although [DataValues.jl](https://github.com/queryverse/DataValues.jl) already exists, I think it’s conceivable to create something like it based on SumTypes.jl. There is also [ResultTypes.jl](https://github.com/iamed2/ResultTypes.jl) that can be implemented based on SumTypes.jl IIUC.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [September 26, 2020, 1:03am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/13 "2020-09-26T01:03:04Z")

</div>

Yes, those are nice examples. Both of those packages essentially are just manually making specific sum types.

It’s reasonable to ask

> how much easier would it be to make these packages with SumTypes.jl?

And the honest answer is “Barely easier” because making a sum type manually isn’t very hard, and the majority of the LOC in those packages are method definitions.

That said, perhaps SumTypes.jl can offer enough utilities in the future that it’d be worth it for them to use it.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [September 26, 2020, 1:37am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/14 "2020-09-26T01:37:44Z")

</div>

> [@Mason](#):
>
> That said, perhaps SumTypes.jl can offer enough utilities in the future that it’d be worth it for them to use it.

Yeah, I’m interested in the tools that SumTypes.jl can provide. For dealing with generic sum types, especially when nested, I imagine having a uniform interface designed from a first principle could be useful.

---

<div class="post-metadata">

**Author:** ![o314](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/o314/32/252_2.png) [@o314](https://discourse.julialang.org/u/o314)\
**Post date:** [September 26, 2020, 4:40am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/15 "2020-09-26T04:40:14Z")

</div>

Typing in julia is not that perfect.

- Empty branch type / Fields on leaf type only is very opionated

- Single inheritance everywhere with abstract is very opionated too.

- Unnamed union, named struct.

- Traits. Are they in the language ?  
Rust has brought the whole prolog to its compiler for them.  
And Julia?

- etc.

Actually Julia is the Killer language thanks to multidispatch. I can’t write code more than 5 minutes without relying to it. That’s the feature that keep me away from Rust. A killer language too.  
_And truly, the lisp wisdom that generative typesystem eg. macro is frequently greater than parametric typesystem eg. cpp template madness_

But the typesystem is not at the same level. (due also to its so many implementation languages, eg. lisp/julia/c++/llvm)

IMHO, Enhancing / Fixing the typesystem in Julia is one of the great challenge of the decade.  
So let’s experiment, and welcome to SumType. It’s good too, if the author has capitalized some knowledge from MLStyle

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [September 26, 2020, 9:09am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/16 "2020-09-26T09:09:21Z")

</div>

> [@o314](#):
>
> Fixing the typesystem in Julia is one of the great challenge of the decade

I wasn’t aware of the type system being broken.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [September 26, 2020, 10:15am UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/17 "2020-09-26T10:15:26Z")

</div>

> [@tkf](#):
>
> People sometimes want a missing value of "type `Union{Missing,T}` " (which is of course impossible with the `missing` we have)

Would that be similar to a ‘parameterized missing’, `Missing{T}`, or is it something else?

---

<div class="post-metadata">

**Author:** ![o314](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/o314/32/252_2.png) [@o314](https://discourse.julialang.org/u/o314)\
**Post date:** [September 26, 2020, 4:07pm UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/18 "2020-09-26T16:07:21Z")

</div>

This post was temporarily hidden by the community for possibly being off-topic, unfocused, inappropriate, or spammy.

---

<div class="post-metadata">

**Author:** ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)\
**Post date:** [September 26, 2020, 4:13pm UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/19 "2020-09-26T16:13:35Z")

</div>

Don’t resort to petty attacks when you make unfounded claims and get called on it.

I bet Tamas still gives you a heart for replying to him anyway though.

---

<div class="post-metadata">

**Author:** ![favba](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/favba/32/2735_2.png) [@favba](https://discourse.julialang.org/u/favba)\
**Post date:** [September 26, 2020, 4:15pm UTC](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161/20 "2020-09-26T16:15:08Z")

</div>

How does having knowledge on a particular field makes one less proficient on another one? That’s absurd.

[Next page](https://discourse.julialang.org/t/ann-sumtypes-jl-0-1/47161.md?page=2)
