Simple, just use the default our scope without a surrounding unit anything.
unit was only added so that you wouldn't have to surround a whole file with { and } when there was only one module, package, class, role, or sub in the file.
You don't always have to use it.
In fact you never have to use it.
If you want, add a forward declaration without a parameterization.
A trait added to it will generally apply to all of the roles with the same name.
lib/Foo/Bar.rakumod:
use v6.d;
role Foo::Bar {…} # is export would be added here
role Foo::Bar[Int:D] {
method is-int(::?CLASS:_: --> True) { }
method is-str(::?CLASS:_: --> False) { }
}
role Foo::Bar[Str:D] {
method is-int(::?CLASS:_: --> False) { }
method is-str(::?CLASS:_: --> True) { }
}
Then when you use it, it automatically gets loaded in such a way that it is accessible by fully qualified name.
{
use lib <lib>; # only needed because it is not installed
use Foo::Bar;
say Foo::Bar[ 1].is-int; # True
say Foo::Bar[''].is-str; # True
say Foo::Bar.^name; # Foo::Bar
}
say Foo::Bar.^name; # error: Could not find symbol 'Bar' in 'Foo'
In this case you can put it inside of a module statement so that you wouldn't need to write Foo:: so often.
lib/Foo/Bar.rakumod:
use v6.d;
unit module Foo;
role Bar {…}
role Bar[Int:D] {
method is-int(::?CLASS:_: --> True) { }
method is-str(::?CLASS:_: --> False) { }
}
role Bar[Str:D] {
method is-int(::?CLASS:_: --> False) { }
method is-str(::?CLASS:_: --> True) { }
}
The role is still accessible as Foo::Bar.
I wouldn't be surprised if this resulted in the exact same code as the previous example.
The only reason to add is export is if you wanted it to be exported as Bar instead of Foo::Bar. This applies to both of the above examples.
My guess is that you thought that you always needed to use is export. In many cases you really don't.
unit module Foo::Bar; # default `our` scoped
our sub baz ( --> 'hello world'){}
use Foo::Bar;
say Foo::Bar::baz(); # hello world
# this works because it was declared as `our`
If you wanted to be able to just use baz() while having it inside of the scope of the module, then and only then do you need to export it.
unit module Foo::Bar;
our sub baz ( --> 'hello world') is export {}
use Foo::Bar;
say Foo::Bar::baz(); # hello world
# available because of `is export`
say baz(); # hello world
Note that I still declared it as our so that if someone didn't want you to export it, it is still accessible to them.
use Foo::Bar ();
# say baz(); # baz used at line 1. Did you mean 'bag'?
say Foo::Bar::baz(); # hello world
The whole purpose of is export is to remove the need to use fully qualified names for functions. That it also works for things like roles is a side benefit.