Consider this: sub id (Any $x) returns Any { return($x) } sub length (Str $y) returns Int { ... }
length(id("abc")); Under standard static subtyping rules, this call will perform three different typechecks: 1) "abc".does(Any) # ("abc" as Str) ===> (Any $x) in &id 2) $x.does(Any) # ($x as Any) ===> (returns Any) in &return 3) Any.does(Str) # (returns Any) ===> (Str $y) in &length The final (returns Int) is unimportant here. Obviously, typecheck #3 fails, as Any cannot do Str. Indeed, there is no type literal in the return position that can satisfy this static typecheck for &id, other than the bottom type which would be a subtype for every type. Let's call it All: sub id (Any $x) returns All { return($x) } However, had we used that, #2 will fail, as it would now be checking for $x.does(All), which is guaranteed to fail regardless of whether the check occurs at runtime (Str.does(All)) or compile time (Any.does(All)). Hence, it seems to me that there are only four ways out: A) Omit the #3 check from compile time; at runtime, use the actual type of $x. The "returns" type annotation will not propagate outward to the caller. At compile time, check for #2: Any.does(Any) At runtime, check for #2: "abc".does(Any) check for #3: "abc".does(Str) B) Omit the #2 check from both compile time and runtime; this allows us to write the "returns All" version. At compile time, check for #3: All.does(Str) At runtime, check for #3: "abc".does(Str) C) Make the return type observe both #2 and #3 at compile time, using junctive types to pass both checks: sub id ( Any $x ) returns Any|All { return($x) } D) Make the return type observe both #2 and #3 at compile time, using type variables: sub id ( (::T) $x ) returns ::T { return($x) } At this moment, I don't have a strong preference to either; I'm more curious on whether this topic has been covered before by p6l and @Larry. Thanks, /Autrijus/
pgpqpS9rYqWnB.pgp
Description: PGP signature