Best Way to Resolve Circular Module Loading

Viewed 150

I'm trying to have two different objects that refer to each other and also use type checking on the attributes. When I do this I get Circular module loading detected trying to precompile. Googling gets me https://docs.raku.org/language/faq#Can_I_have_circular_dependencies_between_modules? which states:

Note that Raku has no “1 file = 1 class” limitation, and circular dependencies within a single compilation unit (e.g., file) are possible through stubbing. Therefore another possible solution is to move classes into the same compilation unit.

I'd rather not put both classes into the same unit if I can avoid it. I'm not sure how to accomplish this with stubbing since there is no example. The following is a small example of what I'm trying to do:

Yak.rakumod

unit class Yak;

use YakStore;

has YakStore $.yak-store is rw;

YakStore.rakumod

unit class YakStore;

use Yak;

has Yak $.yak is rw;

yak.rakutest

use lib '.';

use Test;

use Yak;
use YakStore;

plan 2;

my $yak-store = YakStore.new;

my $yak = Yak.new(:$yak-store);

$yak-store.yak = $yak;

isa-ok $yak-store.yak, Yak;
isa-ok $yak.yak-store, YakStore;

Yeah, I know, the test is lame, but I just wanted to illustrate the problem. Thanks!

1 Answers

The best way to deal with circular dependencies is to turn your circle into a triangle – that is, to make both classes that would depend on each other instead depend (at least in part) on some third Role.

Here's how that might look with the example you provided and a Shaveable role (Yaks should be Shaveable, right?):

Shaveable.rakumod

unit role Shaveable;

Yak.rakumod

use YakStore;
use Shaveable;

unit class Yak does Shaveable;

has YakStore $.yak-store is rw;

YakStore.rakumod

use Shaveable;
unit class YakStore;

has Shaveable $.yak is rw;

With that change, the tests in your example now pass.

Related