-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Consider the following example:
Add := struct <T> (
add: (T, T) -> T
)
Colour := struct(r: u8, g: u8, b: u8)
colour_add := Add<Colour>(
add = (a, b) => Colour(a.r + b.r, a.g + b.g, a.b + b.b)
)
main := () => {
c1 := Colour(0, 0, 0)
c2 := Colour(0, 1, 0)
c3 := colour_add.add(c1, c2)
}The ideal situation is that instead of colour_add.add(c1, c2) we can write c1 + c2 or something like Add::add(c1, c2). Since there is only a single instance of Add<Colour>, it would be unambiguous to resolve Add::add(c1, c2) to colour_add.add(c1, c2). For this reason, the following feature could be added:
Each struct field like add can be accessed from the main struct Add by using the :: operator: Add::add. Then, this becomes the following function:
Add::add := <T> => <instance: Add<T>> => (a: T, b: T) -> T => instance.add(a, b)Conceptually, Add::add means to access the field add of some instance of Add that should be somehow inferred. This inference can occur if there exists some, for example, instance colour_add: Add<Colour> defined earlier (as above).
More generally, for a struct
S := struct <T1..TN> (field1: F1...fieldN: FN)we have functions
S::fieldI : <T1...TN> -> <instance: S<T1...TN>> -> FI
= <T1...TN> => <instance: S<T1...TN>> => instance.fieldIfor all I = 1..N
To be more explicit, this is functionality which recovers the benefits of a trait system.