Switch Chains
Separating decisions from actions
My programming language Plum has postfix syntax for switching on enums:
a_bool
% true -> 2
false -> 3
It also has structural typing, enum literals like , and infers types of expressions:
value =
a_bool
% true -> | foo : 2
false -> | bar : "Hi"
Here, the type of is and the type of is . The type of a switch expression is the union of its cases, so (which you can read as "either it's with an payload, or with a payload").
Turns out, structural typing and postfix switches compose really well!
In other languages, I'd often write code like this:
if condition {
// action 1
...
} else {
var value = computation ()
if other_condition ( value ) {
// action 2
...
} else {
// action 3
...
}
}
Note how I interleave the information gathering / decision making with actually doing the action? In Plum, I can cleanly separate them using this pattern:
condition
% true -> | action_1
false ->
value = computation
other_condition value
% true -> | action_2
false -> | action_3
% action_1 -> ...
action_2 -> ...
action_3 -> ...
Here, I construct a value of the type and then immediately switch on it. The comments are gone! The code is now fully self-documenting.
The first complex data structure written in Plum was the standard library's hash map. It uses a typical implementation: A giant array stores the entries and you do linear searches to put entries into a free place and to find them. A key's hash determines where you start the search, so it works in an ammortized runtime of O(1).
The code for putting an item into the map uses the pattern I described above:
raw_put
buckets : ( Array ( Bucket k v )) index : Int key : k value : v
-> ( Array ( Bucket k v ))
= index = index . mod ( buckets . length )
buckets . get index
% filled -> | keep_searching
empty -> | use_this_bucket
tombstone -> | use_this_bucket
% use_this_bucket -> buckets . set index ( | filled : ( & key value ))
keep_searching -> raw_put buckets ( index .+ 1 ) key value
You don't need to understand every detail, but the gist is that I'm creating an enum , and then switch on it to do the corresponding action. Here's another function that uses switch chains:
raw_get_maybe
buckets : ( Array ( Bucket k v )) index : Int key : k equals : (\ k k -> Bool )
-> ( Maybe v )
= index = index . mod ( buckets . length )
buckets . get index
% filled : entry ->
equals ( entry . key ) key
% true -> | found_it : entry . value
false -> | keep_searching
tombstone -> | keep_searching
empty -> | not_in_map
% found_it : value -> | some : value
not_in_map -> | none
keep_searching -> buckets . raw_get_maybe ( index .+ 1 ) key equals
Beautiful!