(How) does raku do class synonyms?

Viewed 109

I have

class Length is Measure export { ... }

I want synonyms that differ only in that the class name is different, I have tried this:

class Distance   is Length is export {}
class Breadth    is Length is export {}
class Width      is Length is export {}
class Height     is Length is export {}
class Depth      is Length is export {}

This kind of works in that $distance ~~ Length, but I also want $length ~~ Distance.

Some kind or coercion would be desirable - eg $length.Distance ~~ Distance to discourage operations like $width = $height + $depth (ie you cannot always add lengths that point along different axes).

Maybe some class kind of := name binding, or a shorthand way to coerce NxN?

Any advice most gratefully received...

2 Answers

This is not yet an answer, but might grow into one.

Is the following heading in useful directions for you? I don't necessarily mean for you to use composition instead of inheritance (role), or direct aliasing (constant), or mixins (but), or a dynamic type constraint (where). The code below is just a quick way to prototype until you provide feedback.

role Measurement {}
role Height does Measurement {}
role Width does Measurement {}
constant Breadth = Width;
say Width;                             # (Width)
say Breadth;                           # (Width)
say ::<Breadth>:kv;                    # (Breadth (Width))
say Breadth ~~ Width;                  # True
say Width ~~ Breadth;                  # True

multi infix:<+>
  (::L Measurement \l, 
       Measurement \r where * !~~ L)
{ fail }

say (42 but Width) + (99 but Breadth); # 141
say (42 but Width) + (99 but Height);  # Failed...

I'd probably need to see a few more usage cases to be hundred percent sure what the best approach is, but at least with respect to ensuring that all length

class A { 
  method ACCEPTS($other) { $other.isa: A }
}

class B is A { }
class C is A { }
class D is A { }

my $b = B.new;
my $c = C.new;
my $d = D.new;

say $b ~~ D; # True
say $d ~~ C; # True
say $c ~~ B; # True

Because the ACCEPTS is defined on A here, that is what will be used for matching against B/C/D. By default, ACCEPTS smart matches using isa($?CLASS), which is why it returns false, but now it'll lock it into using A always.

Another way is to set the class to an alias. This is normally good for when you want to shorten the name of a longer class you imported from a module, but it will work here too:

class A { ... }
our \B = A;   my $b = B.new;
our \C = A;   my $c = C.new;
our \D = A;   my $d = D.new;

say $b ~~ A & C & D; # True

say $b.WHAT; # A
say $b.WHAT; # A
say $b.WHAT; # A

You'll notice that all these claim to be A because they are. All we've done is give another way to access A. This means that not only does B pass for D or A, it's indistinguishable from them because it's identical to them (down to where it's stored in memory).

Related