10

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!

Ken White
  • 123,280
  • 14
  • 225
  • 444
JustThisGuy
  • 1,109
  • 5
  • 10

1 Answers1

10

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.

codesections
  • 8,900
  • 16
  • 50
  • 1
    I do not recommend this artificial Role approach. Classes layout will become confusing really fast when more `Shaveable` animals will be added. Finally you will be forced to do individual pleonasm stubs like `role YakRole` for each class. – Pawel Pabian bbkr May 23 '22 at 21:59
  • @PawelPabianbbkr Do you have an alternative suggestion here? – uzluisf Jun 10 '23 at 13:16
  • @uzluisf No, that is the curse of single pass parsers. Deal with tons of Roles that sometimes split your logic artificially (like this Shaveable example, that has nothing to do with OP intention) or get rid of type validation in chosen class to break circular dependency. – Pawel Pabian bbkr Jun 13 '23 at 10:39