-
Notifications
You must be signed in to change notification settings - Fork 0
Protocols
Clay current allows protocols (or concepts or type classes, if you prefer) to be defined in an ad-hoc way, using CallDefined?:
ForwardCoordinate?(T) = CallDefined?(dereference, T) and CallDefined?(inc, T);
While this works, it leaves the compiler with very little semantic information for error reporting or debugging—it can only report that the pattern match failed, not why. The CallDefined? syntax is also abstracted from actual expression syntax The syntax for declaring a function as taking any type that follows a protocol is also more verbose than it could be:
[T | ForwardCoordinate?(T)]
next(x: T) {
ref ret = x^;
inc(x);
return ref ret;
}
First-class language support for protocols and function definition syntax for protocol-following types would allow for improvements in compiler error reporting and code readability, and would reduce boilerplate in common function definition cases.
Some sort of protocol syntax. An example:
protocol Interval[Point, Distance] {
add(x: Point, y: Distance) Point;
subtract(x: Point, y: Distance) Point;
subtract(x: Point, y: Point) Distance;
}
Primitive for testing protocol membership:
FollowsProtocol?(Interval, Pointer[Char], PtrInt); // == true
FollowsProtocol?(Interval, String, Int); // == false
// Should you be able to ask whether a type X follows Protocol[X, Y] for any Y?
FollowsProtocol?(Interval, Pointer[Char]); // == true
A nicer shorthand might be to have protocol names evaluate to a static true or false value based on whether the index arguments follow the protocol:
Interval[Pointer[Char], PtrInt]; // == true
Interval[String, Int] // == false
// Should you be able to ask whether a type X follows Protocol[X, Y] for any Y?
Interval[Pointer[Char]] // == true
(A problem with that is that it violates the current convention of boolean things having names ending in ?. Perhaps protocol names could still end with ?, which would mesh with the current type predicate convention.)
Shorthand syntax for declaring an overload as taking a value of any type following a single-argument protocol:
foo(x: protocol Interval) { ... }
// is equivalent to
[TX | Interval[TX]] foo(x: TX) { ... }
Multiple-argument protocols will still work with the existing pattern syntax:
[P, D, I | Interval[P, D] and Integer[I]] bar(p: P, d: D, scale: I) = p + (d*i);
Please add comments here.