On Mon, 20 Jul 2020, Gianni Ceccarelli wrote:
> Aside:
>
> ``(sub (Int $ --> Int) {}) ~~ Walkable`` is false, because
> ``:(Int $ --> Int) ~~ :(Numeric $ --> Numeric)`` is false, which is
> correct because function subtypes should be contravariant in the parameter
> types and covariant in the return type (i.e. if the caller passes a
> Numeric, the callback should accept a Numeric or a *more general*
> type, and if the caller expects a Numeric back, the callback should
> return a Numeric or a *more specific* type).
>
> But then ``:(Numeric $ --> Int) ~~ :(Numeric $ --> Numeric)`` is also
> false, and I feel like it should be true. Opinions?
>
My _opinion_ is that you are right, be it only because there exist words
reminiscent of category theory that describe your desired behavior :-)
But the source code of a Signature smartmatching another Signature [1]
explicitly uses smartmatching for the parameter types and uses the
unforgiving container identity operator to compare the return types:
91 return False unless self.returns =:= $topic.returns;
The `eqv` implementation for two Signatures uses `=:=` as well, so this
restriction seems deliberate. Changing the `=:=` to a `.does` call makes
your code snippet work:
$ ./rakudo-m -e 'say :(Numeric $ --> Int) ~~ :(Numeric $ --> Numeric)'
True
but it creates problems with roast that appear to spread multiple parts
of the language. Failing tests are:
t/spec/S10-packages/precompilation.rakudo.moar (Wstat: 65280
Tests: 32 Failed: 0)
t/spec/S02-types/compact.rakudo.moar (Wstat: 256
Tests: 0 Failed: 0)
t/spec/S02-types/native.rakudo.moar (Wstat: 256
Tests: 0 Failed: 0)
t/spec/S06-currying/positional.t (Wstat: 256
Tests: 0 Failed: 0)
t/spec/S06-signature/closure-parameters.rakudo.moar (Wstat: 256
Tests: 21 Failed: 1)
t/spec/S09-typed-arrays/native-int.rakudo.moar (Wstat: 65280
Tests: 169 Failed: 0)
t/spec/S09-typed-arrays/native-num.rakudo.moar (Wstat: 65280
Tests: 157 Failed: 0)
t/spec/S09-typed-arrays/native.t (Wstat: 65280
Tests: 3 Failed: 0)
t/spec/S17-lowlevel/cas-int.t (Wstat: 256
Tests: 0 Failed: 0)
t/spec/S17-promise/nonblocking-await.t (Wstat: 256
Tests: 0 Failed: 0)
t/spec/S32-array/splice.rakudo.moar (Wstat: 256
Tests: 0 Failed: 0)
t/spec/S32-basics/xxPOS-native.t (Wstat: 65280
Tests: 15 Failed: 0)
t/spec/S32-list/iterator.t (Wstat: 65280
Tests: 48 Failed: 0)
t/spec/integration/precompiled.t (Wstat: 256
Tests: 9 Failed: 1)
Some failures are very dubious like this error, resulting in the test
not even starting (there are multiple of this sort, as you can see):
$ ./rakudo-m -Ilib t/spec/S06-currying/positional.t
===SORRY!===
No appropriate parametric role variant available for 'array::intarray'
Maybe my small changes (patch attached) create inconsistencies with these
other parts of the language (oftentimes related to native types?), or maybe
the test suite relies on (hence specifies) non-covariance. I don't know.
Best,
Tobias
[1]
https://github.com/rakudo/rakudo/blob/master/src/core.c/Signature.pm6#L34-L93
PS: I want to note that my first attempt naïvely replaced the `=:=` with
`~~` but this set roast even more on fire which I think is related to `~~`
autothreading on junctions, as opposed to `=:=` and `.does`.
--
"There's an old saying: Don't change anything... ever!" -- Mr. Monk
diff --git a/src/core.c/Signature.pm6 b/src/core.c/Signature.pm6
index ea2b5cabe..72eff7bdd 100644
--- a/src/core.c/Signature.pm6
+++ b/src/core.c/Signature.pm6
@@ -88,7 +88,7 @@ my class Signature { # declared in BOOTSTRAP
return False unless $hasslurpy;
}
}
- return False unless self.returns =:= $topic.returns;
+ return False unless $topic.returns.does(self.returns);
True;
}
@@ -160,7 +160,7 @@ multi sub infix:<eqv>(Signature:D \a, Signature:D \b) {
return False unless a.WHAT =:= b.WHAT;
# different return
- return False unless a.returns =:= b.returns;
+ return False unless a.returns.does(b.returns);
# arity or count mismatch
return False if a.arity != b.arity || a.count != b.count;