I mentioned built-in types (aka primitives) in my last post. It turns out, pattern matching lets Effes be a bit more expressive than the standard “here’s an int, go do int things with it” operations. For instance, imagine a world where divide-by-zero exceptions can’t happen! (Big disclosure: I don’t think I’ve ever actually triggered one, so they’re not actually that big a deal to me. Still, I like the idea of getting rid of them at compile time.)
Integers in Effes work something like this:
type Int = IntZero | InvValue
type IntValue @builtin:
+ (other: Int) -> Int: @builtin
- (other: Int) -> Int: @builtin
* (other: Int) -> Int: @builtin
/ (other: IntValue) -> Int: @builtin
type IntZero: @builtin
...
As you can see, there are actually two int primitives, one for zero and one for everything else. Int
is just an alias for the disjunction of those two types, and most of the basic math operations take two Ints (this
and other
). Division is the exception: the denominator must be an IntValue
specifically. That means it can’t be an IntZero
— and thus that divide-by-zero errors are caught at compile time.
Here’s how you’d use it:
hitsPerMinute = case minutes of
IntZero: Error -- or whatever
IntValue: hits / minutes
In this snippet, minutes
comes in as a standard Int
. We can’t divide by Int
, so we throw minutes
into a case
expression. If minutes
is an IntZero
, the result is explicitly some sort of error; if it’s IntValue
, we can divide by it.
I’m still not sure if I want to do any such trickery for other primitives. I think I won’t, because other primitives don’t have operations that are undefined (ie, throw an exception) for certain inputs. Floating points, for instance, let you divide by zero, add infinity, or do anything else and always get a value back. It may be NaN
, but it’s still a value.
It’s actually a bit interesting to me that other languages don’t have this sort of behavior; all you really need to make it work is pattern matching. My guess is that it’s just not a very compelling problem (as I mentioned earlier, I don’t think I’ve ever actually gotten tripped up by it), so it’s not worth the work to catch it. Effes’ type scheme lets me catch it with minimal compiler trickery, which is probably about as much as it’s worth.