Wallogit.com
2017 © Pedro Peláez
"In computer programming, especially functional programming and type theory, an algebraic data type is a kind of composite type, i.e., a type formed by combining other types." — good old Wikipedia, (*1)
In computer science sum type, is a data structure used to hold a value that could take on several different, but fixed, types. Only one of the types can be in use at any one time, and a tag field explicitly indicates which one is in use., (*2)
Let's say we want to create a type Weekday. We want it to be limited to the possible 7 days in the week: Sunday, Monday, Tuesday, Wednesday, Thursday, Friday and Saturday., (*3)
We could do that in a number of ways using typical imperative or Object Oriented techniques. We could use enums, constants grouped under an interface or inheritance., (*4)
At the moment PHP does not have enums, so that one is not a choice., (*5)
Grouping constants in a interface is a popular alternative, but it does not give any type safety., (*6)
<?php
interface WeekDay {
const SUNDAY = 'Sunday',
MONDAY = 'Monday',
TUESDAY = 'Tuesday',
WEDNESDAY = 'Wednesday',
THURSDAY = 'Thursday',
FRIDAY = 'Friday',
SATURDAY = 'Saturday';
}
When passing a weekday to a function I cannot specify the Weekday type as a type hint., (*7)
Finally we could try extending a super class or implementing a common interface., (*8)
<?php
interface Weekday {}
final class Sunday implements Weekday { }
final class Monday implements Weekday { }
//...
Now we can type hint Weekday we passing it around:, (*9)
<?php
function orderPizza(Weekday $weekday, Pizza $pizza)
{
switch (get_class($weekday)) {
case Wednesday::class : return new WednesdayPromotionOrder($pizza);
default : return new Order($pizza);
}
}
There is, however, no way in PHP to guarantee that the interface won't be extended beyond the ones distributed with the library. Nothing stops a Pluto fan from:, (*10)
<?php
final class Plutoday implements Weekday { }
And all of a sudden we can now order pizza in weird days. But fear not! Sum types is there to save us from that madness., (*11)
First we create a type constructor Weekday. PHP only way to create hintable types is through classes. So, let's use
that., (*12)
<?php
abstract class Weekday implements TypeConstructor { use SumType; }
Then we seal it. Let's use ImmutableSealed to add immutablity while we are at
it, (*13)
<?php
abstract class Weekday extends ImmutableSealed implements TypeConstructor { use SumType; }
ImmutableSealed requires us to tell what is the types the type constructor can create, (*14)
<?php
abstract class Weekday extends ImmutableSealed implements TypeConstructor, SumTypeTag {
const sealedTo = [ Sunday::class, Monday::class, Tuesday::class,
Wednesday::class, Thursday::class, Friday::class, Saturday::class];
public function __construct() { $this->applySeal(); }
}
We still need to create the sum types:, (*15)
<?php
final class Sunday extends Weekday { use SumType; const typeConstructor = Weekday::class; }
final class Monday extends Weekday { use SumType; const typeConstructor = Weekday::class; }
//...
final class Saturday extends Weekday { use SumType; const typeConstructor = Weekday::class; }
If we try to extend Weekday outside the seal we get a type error., (*16)
<?php
final class Plotoday extends Weekday { use SumType; const typeConstructor = Weekday::class; }
new Plutoday; // results in:
// TypeError has been thrown with message: "Weekday is sealed and cannot be extended outside seal."