-
Notifications
You must be signed in to change notification settings - Fork 22
Description
Sum types, 2025 variant
We tweak case inside objects to offer:
- Type safety: field accesses are checked entirely at compile time.
- Conciseness: The duplication of enum field declarations and their usage in
caseobjects is removed. - Conciseness: Constructing an instance of a sum type is shorter:
BinaryOpr(a: a, b: b)instead ofNode(kind: BinaryOpr, a: a, b: b). - Pattern matching.
This year's proposal accomplishes all of the above with a simple syntactic tweak of the existing case objects.
The "discriminator" can now be left out. If it is left out, the entire object is a so called "new style case object".
type
Node = ref object
case
of AddOpr, SubOpr, MulOpr, DivOpr:
a, b: Node
of UnaryOpr:
a: Node
of Variable:
name: string
of Value:
val: int
# "shared" fields are directly supported:
info: LineInfo
The "branch names" (e.g. AddOpr, UnaryOpr, etc.) are used
for construction and pattern matching.
Construction
Construction is done with the syntax Branch(fieldNameA: valueA, fieldNameB: valueB, ...). (A shortcut
for this should be added later, in a separate proposal that affects all object types!)
To access the attached values, pattern matching must be used. This enforces correct access at compile-time.
Pattern matching
The syntax of BranchName(fields...) is used for pattern matching:
proc traverse(n: Node) =
case n
of {AddOpr, SubOpr, MulOpr, DivOpr}(a, b):
traverse a
traverse b
of UnaryOpr(a):
traverse a
of Variable(name):
echo name
of Value(x):
counter += x
Whether the local variables (a, b, name, x in the above example) are mutable or not depends on the
mutability of expression that is being matched:
var x = Some(90)
case x
of Some(y):
y = 180 # writes to `x`
of None:
echo "no value"Serialization
As before, traverse the type's AST in a macro to generate the store and load procedures. No special
additions are included in this proposal.
Future directions
- Allow object construction to leave out the field names:
MyObject(1, 2)instead ofMyObject(a: 1, b: 2). - Allow for a
casetype to be written outside of anobjectand allow field names to be left out:
type
Option[T] =
case
of Some: T
of None: discard
Either[A, B] =
case
of Left: A
of Right: BWould be short for:
type
Option[T] = object
case
of Some:
_: T
of None:
_: discard
Either[A, B] = object
case
of Left:
_: A
of Right:
_: B