compiler
compiler copied to clipboard
Tagged unions / sealed classes
See https://wiki.php.net/rfc/tagged_unions:
// Declaration
enum Distance {
case Kilometers(public int $km);
case Miles(public int $miles);
}
// Usage
$walk= Distance::Miles(500);
print $walk->miles; // prints "500"
The famous "Maybe" nomad:
// Declaration
enum Optional {
case None {
public function bind(callable $f) { return $this; }
public function value(): mixed { return null; }
};
case Some(private mixed $value) {
public function bind(callable $f): Optional { return Optional::of($f($this->value)); }
public function value(): mixed { return $this->value; }
};
public static function of($value): self {
return $value instanceof self ? $value : ($value ? self::Some($value) : self::None);
}
}
// Usage
$value= Optional::of($record)->bind(fn($r) => $r['distance'] + 1)->value();
These are very similar to Kotlin's sealed classes: In some sense, sealed classes are similar to enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances, each with its own state..
See also https://www.dotnetcurry.com/patterns-practices/1510/maybe-monad-csharp
First implementation idea:
// What the user writes
enum Distance {
case Miles(public int $miles);
}
// What gets emitted
abstract class Distance implements \TaggedUnion {
public static function Miles(int $miles): self {
return new class('Miles', $miles) extends self {
public $name, $miles;
private function __construct($name, $miles) {
$this->name= $name;
$this->miles= $miles;
}
};
}
}