Is there a straightforward way to check if something is a mixin?

Viewed 136

Raku mixins have two (or more) natures, combining several values in the same container, or values along with roles. However, there is not, as far as I can tell, a straightforward way to check for "mixinity" in a variable that has not been created by you.

This might be a trick

my $foo = 3 but Stringy;
say $foo.^name ~~ /\+/;# OUTPUT: «「+」␤»

But is there any other property I'm missing that would allow to look this up directly?

3 Answers

I think you're missing the ^roles and ^parents meta-methods:

my $foo = 3 but Stringy;
dd $foo.^roles;   # (Stringy, Real, Numeric)
dd $foo.^parents; # (Int,)

TL;DR My unreliable solution[1] is simpler and faster than your unreliable solution[2] and should work for question Y and maybe question X[3]:

sub is-mixin ($object) { $object.^is_mixin =:= 1 }
say is-mixin 3;           # False
say is-mixin 3 but 'bar'; # True

Footnotes

[1] "Warning: [role Metamodel::Mixins] is part of the Rakudo implementation, and is not a part of the language specification."

[2] I haven't searched roast but would imagine that the use of + in type names is just a convention, not a part of the language specification.

[3] I found your question to be an example of either the XY problem, per my first comment below it; and/or of terminological confusion, per my second. The rest of this answer explains what I mean.

Is there a straightforward way to check if a container is a mixin?

The word "container" has a technical meaning in Raku. It refers to a value that follows Raku's container protocol. The container protocol applies when a value is followed by = to invoke "assignment".

What you are asking about appears to have nothing to do with such a container, as something distinct from a value. And there's good reason to think that that doesn't matter to you -- that what you are just interested in is testing if a value is a mixin, and the "container" aspect is a red-herring, either because you didn't mean "container" in the usual sense in Raku, or because it doesn't matter anyway because a container is a value, so whatever works for testing a value will work for testing a container.

For example, looking at your "trick":

my $foo = 3 but Stringy;
say $foo.^name ~~ /\+/;# OUTPUT: «「+」␤»

This trick is unrelated to any container aspect using the normal technical use of the word "container" in Raku. You get the same result if you write the following that doesn't involve a container: say (3 but Stringy).^name ~~ /\+/;# OUTPUT: «「+」␤».

So in my solution I've presumed you just meant a value, knowing that it actually doesn't matter whether or not your ultimate focus is on a container.

If I'm wrong about my presumption, and it makes a difference, I urge you to explain the X of what it is you're trying to do rather than just the Y.

Your trick makes your code brittle because it doesn't expect

$foo.^set_name('The Spanish Inquisition');

Of course nobody does :)

You better just ask the Rakudo Metamodel:

say $foo.^is_mixin; # OUTPUT: «1␤»

Two things to note:

  1. The is_mixin metamethod does not return a Bool
  2. Like the name metamethod it is specific to the Rakudo implementation of Raku
Related