role Metamodel::Mixins

Metaobject for generating mixins

role Metamodel::Mixins {}

Warning: this role is part of the Rakudo implementation, and is not a part of the language specification.

Using the does and but infix operators, mixins of a base object and an arbitrary number of roles (or another object) can be created. These are objects whose types have properties of both operands' types. Respectively, these rebless the existing object to have the generated mixin type and clone said object with said mixin type:

class Billboard {
    has Str:D $.advertisement is required;
 
    method vandalism(::?CLASS:D: --> Str:D{ ... }
 
    multi method Str(::?CLASS:D: --> Str:D{ $!advertisement }
 
    role Vandalized[Str:D :$vandalism{
        method vandalism(::?CLASS:D: --> Str:D{ $vandalism }
 
        multi method Str(::?CLASS:D: --> Str:D{ $vandalism }
    }
}
 
my Str:D $advertisement = Q:to/ADVERTISEMENT/.chomp; 
Brilliant Solutions: sane and knowledgeable consultants.
We have been providing excellent services since 1972!
ADVERTISEMENT
my Str:D $vandalism = Q:to/VANDALISM/.chomp; 
          S       s  s ne     k          l   o   l     .
We    e  ee            e  e  e    e    e      e     !
VANDALISM
 
my Billboard:D $billboard .= new: :$advertisement;
say $billboard eq $advertisement# OUTPUT: «True␤» 
 
my Billboard:D $draft = $billboard but Billboard::Vandalized[:$vandalism];
say $draft eq $vandalism# OUTPUT: «True␤» 
 
$billboard does Billboard::Vandalized[:$vandalism];
say $billboard eq $vandalism# OUTPUT: «True␤» 

Optionally, mixins may have a mixin attribute. This occurs when only one role having only one public attribute gets mixed into an object. If a mixin attribute exists on a resulting mixin's type, it can be initialized by but or does using its value named parameter. This makes it possible for mixins to not only have composable methods, but composable state as well. Using this feature, the example above can be rewritten so billboards can be vandalized more than once without needing to generate more mixins by making Billboard::Vandalism's $vandalism named parameter an rw mixin attribute instead:

class Billboard {
    has Str:D $.advertisement is required;
 
    method vandalism(::?CLASS:D: --> Str:D{ ... }
 
    multi method Str(::?CLASS:D: --> Str:D{ $!advertisement }
 
    role Vandalized {
        has Str:D $.vandalism is required is rw;
 
        multi method Str(::?CLASS:D: --> Str:D{ $!vandalism }
    }
}
 
my Str:D $advertisement = Q:to/ADVERTISEMENT/.chomp; 
Brilliant Solutions: sane and knowledgeable consultants.
We have been providing excellent services since 1972!
ADVERTISEMENT
my Str:D $vandalism = Q:to/VANDALISM/.chomp; 
          S       s  s ne     k          l   o   l     .
We    e  ee            e  e  e    e    e      e     !
VANDALISM
my Str:D $false-alarm = Qs:to/FALSE-ALARM/.chomp;
$vandalism
⬆️ This is just one of our namesakes we at Brilliant Solutions have been
helping people like you create since 1972!
FALSE-ALARM
 
my Billboard:D $billboard .= new: :$advertisement;
say $billboard eq $advertisement# OUTPUT: «True␤» 
 
$billboard does Billboard::Vandalized :value($vandalism);
say $billboard eq $vandalism# OUTPUT: «True␤» 
 
$billboard.vandalism = $false-alarm;
say $billboard eq $false-alarm# OUTPUT: «True␤» 

Metamodel::Mixins is the metarole that implements the behavior of said mixins. Formally, mixins are objects whose HOW inherits from a base composable metaobject and applies an arbitrary number of roles, resulting in an object whose HOW has a combination of their properties. In particular, the metamethods this metarole provides are used to implement the behavior of the but and does infix operators, but these also support introspection related to mixins. For example, the work done by but when invoked with an object and one role can be written explicitly using the mixin metamethod provided:

class Foo { }
role Bar { }
 
say Foo.new but Bar;     # OUTPUT: «Foo+{Bar}.new␤» 
say Foo.new.^mixin(Bar); # OUTPUT: «Foo+{Bar}.new␤» 

Methods

method set_is_mixin

method set_is_mixin($obj)

Marks $obj as being a mixin.

method is_mixin

method is_mixin($obj)

Returns 1 If $obj has been marked as being a mixin with set_is_mixin, otherwise returns 0.

method set_mixin_attribute

method set_mixin_attribute($obj$attr)

Sets the mixin attribute for $obj to $attr (which should be an Attribute instance).

method mixin_attribute

method mixin_attribute($obj)

Returns the mixin attribute for $obj set with set_mixin_attribute.

method setup_mixin_cache

method setup_mixin_cache($obj)

Sets up caching of mixins for $obj. After this metamethod has been called, calls to mixin will not create a new type for mixins of $obj given the same list of roles more than once. This should be called at some point before composition.

method flush_cache

method flush_cache($obj)

No-op.

method generate_mixin

method generate_mixin($obj@roles)

Creates a new mixin metaobject that inherits from $obj and does each of the roles in @roles. This is then composed and has its mixin attribute set (if any exists) before getting returned.

While this generates a new mixin type, this doesn't actually mix it into $obj; if that is what you intend to do, use the mixin metamethod instead.

method mixin

method mixin($obj*@roles:$needs-mixin-attribute)

Generates a new mixin type by calling generate_mixin with $obj and @roles. If $obj is composed, the mixin cache of $obj will be checked for any existing mixin for these beforehand. If $obj is an instance of a type, this will return $obj reblessed with the mixin generated, otherwise this will return the mixin itself.

If $needs-mixin-attribute is True, this will throw an exception if no mixin attribute exists on the mixin generated before returning.

Type Graph

Type relations for Metamodel::Mixins
perl6-type-graph Metamodel::Mixins Metamodel::Mixins Mu Mu Any Any Any->Mu Metamodel::Naming Metamodel::Naming Metamodel::Stashing Metamodel::Stashing Metamodel::AttributeContainer Metamodel::AttributeContainer Metamodel::MethodContainer Metamodel::MethodContainer Metamodel::MultiMethodContainer Metamodel::MultiMethodContainer Metamodel::RoleContainer Metamodel::RoleContainer Metamodel::BaseType Metamodel::BaseType Metamodel::MROBasedMethodDispatch Metamodel::MROBasedMethodDispatch Metamodel::MROBasedTypeChecking Metamodel::MROBasedTypeChecking Metamodel::BUILDPLAN Metamodel::BUILDPLAN Metamodel::BoolificationProtocol Metamodel::BoolificationProtocol Metamodel::EnumHOW Metamodel::EnumHOW Metamodel::EnumHOW->Metamodel::Mixins Metamodel::EnumHOW->Any Metamodel::EnumHOW->Metamodel::Naming Metamodel::EnumHOW->Metamodel::Stashing Metamodel::EnumHOW->Metamodel::AttributeContainer Metamodel::EnumHOW->Metamodel::MethodContainer Metamodel::EnumHOW->Metamodel::MultiMethodContainer Metamodel::EnumHOW->Metamodel::RoleContainer Metamodel::EnumHOW->Metamodel::BaseType Metamodel::EnumHOW->Metamodel::MROBasedMethodDispatch Metamodel::EnumHOW->Metamodel::MROBasedTypeChecking Metamodel::EnumHOW->Metamodel::BUILDPLAN Metamodel::EnumHOW->Metamodel::BoolificationProtocol Metamodel::Documenting Metamodel::Documenting Metamodel::Versioning Metamodel::Versioning Metamodel::Finalization Metamodel::Finalization Metamodel::PrivateMethodContainer Metamodel::PrivateMethodContainer Metamodel::MultipleInheritance Metamodel::MultipleInheritance Metamodel::DefaultParent Metamodel::DefaultParent Metamodel::C3MRO Metamodel::C3MRO Metamodel::Trusting Metamodel::Trusting Metamodel::ClassHOW Metamodel::ClassHOW Metamodel::ClassHOW->Metamodel::Mixins Metamodel::ClassHOW->Any Metamodel::ClassHOW->Metamodel::Naming Metamodel::ClassHOW->Metamodel::Stashing Metamodel::ClassHOW->Metamodel::AttributeContainer Metamodel::ClassHOW->Metamodel::MethodContainer Metamodel::ClassHOW->Metamodel::MultiMethodContainer Metamodel::ClassHOW->Metamodel::RoleContainer Metamodel::ClassHOW->Metamodel::MROBasedMethodDispatch Metamodel::ClassHOW->Metamodel::MROBasedTypeChecking Metamodel::ClassHOW->Metamodel::BUILDPLAN Metamodel::ClassHOW->Metamodel::BoolificationProtocol Metamodel::ClassHOW->Metamodel::Documenting Metamodel::ClassHOW->Metamodel::Versioning Metamodel::ClassHOW->Metamodel::Finalization Metamodel::ClassHOW->Metamodel::PrivateMethodContainer Metamodel::ClassHOW->Metamodel::MultipleInheritance Metamodel::ClassHOW->Metamodel::DefaultParent Metamodel::ClassHOW->Metamodel::C3MRO Metamodel::ClassHOW->Metamodel::Trusting

Expand above chart