it says 'use lib' may not be pre-compiled
This has now been fixed per @codesections++'s comment below.
perhaps because of circular dependentness
No. use lib
can only be used by the main program file, the one directly run by Rakudo.
Is there a way I can achieve this?
Here's one way.
We introduce a new file that's use
d by the other packages to eliminate the circularity. So now we have four files (I've rationalized the naming to stick to A
or variants of it for the packages that contribute to the type A
):
A-sawn.rakumod
that's a role
or class
or similar:
unit role A-sawn;
Other packages that are to be separated out into their own files use
the new "sawn" package and does
or is
it as appropriate:
use A-sawn;
unit class A-Ops does A-sawn;
multi prefix:<++>(A-sawn:D $obj) is export { ++($obj.x) }
multi postfix:<++>(A-sawn:D $obj) is export { ($obj.x)++ }
The A.rakumod
file for the A
type does the same thing. It also use
s whatever other packages are to be pulled into the same A
namespace; this will import symbols from it according to Raku's standard importing rules. And then relevant symbols are explicitly exported:
use A-sawn;
use A-Ops;
sub EXPORT { Map.new: OUTER:: .grep: /'fix:<'/ }
unit class A does A-sawn;
has $.x is rw;
Finally, with this setup in place, the main program can just use A;
:
use lib '.';
use A;
my $a = A.new(x => -1);
say $a++; # A.new(x => -1)
say ++$a; # A.new(x => 1)
say ++$a; # A.new(x => 2)
The two main things here are:
Introducing an (empty) A-sawn
package
This type eliminates circularity using the technique shown in @codesection's answer to Best Way to Resolve Circular Module Loading.
Raku culture has a fun generic term/meme for techniques that cut through circular problems: "circular saws". So I've used a -sawn
suffix of the "sawn" typename as a convention when using this technique.[1]
Importing symbols into a package and then re-exporting them
This is done via sub EXPORT { Map.new: ... }
.[2] See the doc for sub EXPORT
.
The Map
must contain a list of symbols (Pair
s). For this case I've grepped through keys from the OUTER::
pseudopackage that refers to the symbol table of the lexical scope immediately outside the sub EXPORT
the OUTER::
appears in. This is of course the lexical scope into which some symbols (for operators) have just been imported by the use Ops;
statement. I then grep that symbol table for keys containing fix:<
; this will catch all symbol keys with that string in their name (so infix:<...
, prefix:<...
etc.). Alter this code as needed to suit your needs.[3]
Footnotes
[1] As things stands this technique means coming up with a new name that's different from the one use
d by the consumer of the new type, one that won't conflict with any other packages. This suggests a suffix. I think -sawn
is a reasonable choice for an unusual and distinctive and mnemonic suffix. That said, I imagine someone will eventually package this process up into a new language construct that does the work behind the scenes, generating the name and automating away the manual changes one has to make to packages with the shown technique.
[2] A critically important point is that, if a sub EXPORT
is to do what you want, it must be placed outside the package definition to which it applies. And that in turn means it must be before a unit
package declaration. And that in turn means any use
statement relied on by that sub EXPORT
must appear within the same or outer lexical scope. (This is explained in the doc but I think it bears summarizing here to try head off much head scratching because there's no error message if it's in the wrong place.)
[3] As with the circularity saw aspect discussed in footnote 1, I imagine someone will also eventually package up this import-and-export mechanism into a new construct, or, perhaps even better, an enhancement of Raku's built in use
statement.