Overloading Without Ambiguity
Modern language design often shuns features such as overloading and implicit conversions. We have found that they are harmless so long as their method of operation is fully unambiguous.
No Overload Resolution Order
When resolving a call, every function is considered equally viable. Every function, template, type and conversion is taken into account, and if the callsite can match more than one overload, it will fail to compile. This rule has no exceptions, and results in a simple guarantee:
- Removing any definition currently in use will result in a compile time error.
This may sound like a no-brainer but is generally not the case in languages with overloading.
case
Patterns
Template functions can have one or more
patterns, evaluated top to bottom.
case
fn sum(v: <T>[])
case (T.is::arithmetic): T {
mut ret: T
v.each: |it| ret += it
return ret
}
case (T.is::flags): T {
mut ret: T
v.each: |it| ret |= it
return ret
}
The definition above could be split if needed, in which case both are evaluated on equal terms, and an ambiguity error will be raised if both match:
fn sum(v: <T>[]) case (T.is::arithmetic): T {
mut ret: T
v.each: |it| ret += it
return ret
}
fn sum(v: <T>[]) case (T.is::flags): T {
mut ret: T
v.each: |it| ret |= it
return ret
}
Template Argument Constraints
Note the type annotation to the
arguments above. We simultaneously used v<T>
above to introduce a new type parameter
and used T
to constrain the argument to an array of that type.
[]
TODO
Argument .autocall
Patterns
TODO
Operator Overloading
struct BitSet { data: u8[] }
infix fn |=(ref .data left, .data right) {
left.grow(max(left.len, right.len))
right.each: |v, i| left[i] |= v
}
TODO