Language Design: The Benefits of Type Unions
Published on 2021-08-26. Last updated on 2026-07-28
Overview
| Syntactic Wrapping | No Syntactic Wrapping | |
|---|---|---|
| No Runtime Tags | untagged union (C union, C++ union, Rust union) |
union type (TypeScript union type) |
| Runtime Tags | discriminated union/tagged union (Rust enum, F# discriminated union) |
type union (Algol united mode, Core union, C# union) |
Benefits of Type Unions
Union variants are types, and refer to a “real” class/struct/… definition
This fixes a mistake that some languages like Rust or Haskell made with their enum/data types.12
It also means that variants can be reference types or value types (as they refer to existing type definitions).
Example
class Cat(let name: String, let lives: Int64) class Dog(let name: String, let years: Int64) union Pet of Cat, Dog // accepts both cats and dogs fun pet(pet: Pet) = ... // accepts only dogs fun playFetch(dog: Dog) = ...
No “stutter”, where variant names have to be invented to wrap existing types
This reduces syntactic indirection at definition-sites. (Rust has this issue.)
Example
Instead of ...
enum JsonValue {
JsonObject(Map[String, JsonValue])
JsonArray (Array[JsonValue]),
JsonString(String),
JsonNumber(Float64),
JsonBool (Bool),
JsonNull,
...
}
... one would write (with Array, Float64 and String being existing types in the language):
union JsonValue of Map[String, JsonValue] Array[JsonValue], String, Float64 Bool, JsonNull, ... value JsonNull
Union values can be passed/created more easily, as no syntactic wrapping is required
This reduces syntactic indirection at use-sites and allows “variants” to be used in more scenarios (compared to more “traditional” enums).
Example
No wrapping required when passing arguments (unlike "traditional" enum approaches):
fun someValue(value: JsonValue) = ...
someValue(JsonString("test")) // "traditional" approach
someValue("test") // proposed union design
Variants can be used in multiple unions.
Example
Consider this class definition:class Name(name: String)With the proposed union design,
Name can be used multiple times: in different unions, and elsewhere.
union PersonIdentifier of Name, ... // other identifiers like TaxId, Description, PhoneNumber etc. union DogTag of Name, ... // other identifiers like RegId, ...