[fine] Design for "intersection" types
This commit is contained in:
parent
f634e4da18
commit
019d780f85
1 changed files with 129 additions and 0 deletions
129
fine/tests/expression/alternates.fine
Normal file
129
fine/tests/expression/alternates.fine
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// Examples of alternate types/union types/heterogeneous types.
|
||||
class Foo {
|
||||
x: f64;
|
||||
}
|
||||
|
||||
class Bar {
|
||||
y: f64;
|
||||
}
|
||||
|
||||
fun extract_value(v: Foo or Bar) -> f64 {
|
||||
if match v as Foo {
|
||||
v.x // Magic type binding!
|
||||
} else as Bar {
|
||||
v.y // Same magic re-binding of the variable to the new type
|
||||
} // No error; exhaustivity analysis should work.
|
||||
}
|
||||
|
||||
// This is Bob Nystrom's example from
|
||||
// https://journal.stuffwithstuff.com/2023/08/04/representing-heterogeneous-data/
|
||||
//
|
||||
class MeleeWeapon {
|
||||
damage: f64;
|
||||
}
|
||||
|
||||
class RangedWeapon {
|
||||
minRange: f64;
|
||||
maxRange: f64;
|
||||
}
|
||||
|
||||
class Monster {
|
||||
health: f64;
|
||||
}
|
||||
|
||||
fun print(x:string) {}
|
||||
|
||||
fun in_range(weapon: MeleeWeapon or RangedWeapon, distance: f64) {
|
||||
if match weapon as w : RangedWeapon {
|
||||
distance >= w.minRange and distance <= w.maxRange
|
||||
} else {
|
||||
distance == 1
|
||||
}
|
||||
}
|
||||
|
||||
fun attack(weapon: MeleeWeapon or RangedWeapon, monster: Monster, distance: f64) {
|
||||
// This is worse but it works.
|
||||
if match weapon as MeleeWeapon and distance > 1 or
|
||||
match weapon as w:RangedWeapon and (distance < w.minRange or distance > w.maxRange) {
|
||||
print("You are out of range")
|
||||
return
|
||||
}
|
||||
|
||||
// Bob says he doesn't want to do flow analysis but we're doing all our
|
||||
// tricks with variables and scoping here, with one *big* bit of magic which
|
||||
// is...
|
||||
//
|
||||
// NOTE: special syntax here: `identifier` as `TypeExpression` ALMOST means
|
||||
// `identifier as identifier : TypeExpression` as the shorthand for checking
|
||||
// local variables. The *almost* part is that the effective type of the
|
||||
// variable changes but not the binding. (Is this what we want?)
|
||||
let damage = if match weapon as w: MeleeWeapon {
|
||||
roll_dice(w.damage)
|
||||
} else as w: RangedWeapon {
|
||||
// This is the trick here: else as re-uses the expression from the match
|
||||
// and so we can do exhaustivity analysis.
|
||||
w.maxRange - w.minRange
|
||||
};
|
||||
|
||||
if monster.health <= damage {
|
||||
print("You kill the monster!");
|
||||
monster.health = 0
|
||||
} else {
|
||||
print("You wound the monster.");
|
||||
monster.health = monster.health - damage
|
||||
}
|
||||
}
|
||||
|
||||
fun more_examples(weapon: MeleeWeapon or RangedWeapon) -> f64 or () {
|
||||
if match weapon as w: RangedWeapon and w.maxRange > 10 {
|
||||
// w is still in scope here; the `and` is bound into a predicate expression
|
||||
// and breaks exhaustivity
|
||||
w.minRange
|
||||
}
|
||||
}
|
||||
|
||||
// Some fun with iterators
|
||||
|
||||
class Iterator {
|
||||
current: f64;
|
||||
|
||||
fun next(self) -> f64 or () {
|
||||
if self.current < 10 {
|
||||
let result = self.current;
|
||||
self.current = self.current + 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test() -> f64 {
|
||||
let sum = 0;
|
||||
|
||||
// A single step of an iterator...
|
||||
let it = new Iterator { current: 0 };
|
||||
if match it.next() as v: f64 {
|
||||
sum = sum + v;
|
||||
}
|
||||
|
||||
// Looping by hand over an iterator is pretty clean.
|
||||
let it = new Iterator { current: 0 };
|
||||
while match it.next() as v: f64 {
|
||||
sum = sum + v;
|
||||
}
|
||||
|
||||
// Unroll by hand...
|
||||
let it = new Iterator { current: 0 };
|
||||
loop {
|
||||
if match it.next() as v: f64 {
|
||||
sum = sum + v;
|
||||
} else {
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
||||
// Not in this test but `for` over an object should turn into something
|
||||
// like the above.
|
||||
}
|
||||
|
||||
// @ignore WIP
|
||||
// @no-errors
|
||||
Loading…
Add table
Add a link
Reference in a new issue