I am making a module that has multi module file, and faced this problem when using role in different module.
For example we have two module Foo and Bar, and there is a role in each module.
module Foo {
role foo is export {
}
}
module Bar {
import Foo;
role bar is export does foo {
}
}
import Foo;
import Bar;
sub f(foo \k) { }
f(bar.new);
I thought the code is fine, but rakudo said it think bar is not a foo and reject to compile.
What's wrong here ?
Update in 2022 I just checked and in v2022.02 this code now works as expected.
The symbol foo
after import
isn't =:=
to Foo::foo
and doesn't accept the latter in a smart match. That seems like a bug to me and is presumably related to what's going on:
module Foo {
role foo is export { }
.say for foo.^name, Foo::foo.^name,
Foo.WHICH, foo.WHICH, Foo::foo.WHICH,
foo.isa(Foo::foo),
Foo::foo.isa(foo),
foo.does(Foo::foo),
Foo::foo.does(foo),
foo ~~ Foo::foo,
Foo::foo ~~ foo,
}
import Foo;
.say for foo.^name, Foo::foo.^name,
Foo.WHICH, foo.WHICH, Foo::foo.WHICH,
foo.isa(Foo::foo),
Foo::foo.isa(foo),
foo.does(Foo::foo),
Foo::foo.does(foo),
foo ~~ Foo::foo,
Foo::foo ~~ foo,
Foo::foo
Foo::foo
Foo|U64545472
Foo::foo|U64545856
Foo::foo|U64545856
False
False
True
True
True
True
Foo::foo
Foo::foo
Foo|U64545472 <^-- all good so far
Foo::foo|U64545616 <--- uhoh
Foo::foo|U64545856
False
False
True
True
True
False <-- presumably a consequence of uhoh
I'll file a bug in the next couple days if no one beats me to it and no one shows why it's not a bug.
This looks like a bug to me. Some further investigation:
module Foo {
role Bar is export {}
}
module Quux {
import Foo;
constant Barr = Bar;
role Baz does Bar is export {}
role Bazz does Foo::Bar is export {}
}
import Foo;
import Quux;
# these are all the same:
say Foo::EXPORT::ALL::Bar.WHICH;
say Quux::Barr.WHICH;
say Bar.WHICH;
# but different from our original type object!?!
say Foo::Bar.WHICH;
# now it gets weird:
say Baz ~~ Bar; # True
say Baz.new ~~ Bar; # False
say Baz ~~ Foo::Bar; # False
say Baz.new ~~ Foo::Bar; # True
# however, these all 'work':
say Bazz ~~ Bar; # True
say Bazz.new ~~ Bar; # True
say Bazz ~~ Foo::Bar; # True
say Bazz.new ~~ Foo::Bar; # True
For now, it seems best to only derive new roles from the fully qualified public version of another module's role instead of an exported one: Exporting seems to create a new type object that interacts strangely with smart matching/type checking...
Let me see if I can channel @raiph and answer this question in the best way possible. There are several errors here.
Using import
The main use case for import
is exactly the one you do here; it's described in the documentation. However, it's a better practice to put modules in different files (with the same name as the module) and go for use
instead. use
which imports and includes everything into the namespace. use
loads (via need
) and then imports the module exactly once.
Save curly braces using unit
unit
is basically syntactic sugar to save braces. So the first two files will become:
Foo.pm6
unit module Foo;
role foo is export {
}
Bar.pm6
unit module Bar;
use Foo;
role bar is export does foo {}
The use
of Foo
imports the foo
symbol directly, and it can be used as a role.
What is a role
Last but not least, a role mixed in does is literally a "does" declaration. It's not an "is-a" declaration. So bar
can do
foo, but it's not foo
. Which makes the last file something like this:
use-foo-bar.p6
:
use Foo;
use Bar;
sub f(bar \k) { }
f(bar.new);
Note that I have used bar \k
instead of foo \k
. If I didn't, the error would be: Type check failed in binding to parameter 'k'; expected Foo::foo but got Bar::bar (Bar::bar.new)
Back to the original post
What was wrong was simply the sub declaration, which should have been:
sub f(bar \k) { }
Due to what is explained in the last section above. However, I needed to examine a bit the rest of the program to find this out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With