2 package Moose::Meta::SafeMixin;
7 use Scalar::Util 'blessed';
10 our $VERSION = '0.01';
12 use base 'Class::MOP::Class';
15 # fetch the metaclass for the
16 # caller and the mixin arg
17 my $metaclass = shift;
18 my $mixin = $metaclass->initialize(shift);
20 # according to Scala, the
21 # the superclass of our class
22 # must be a subclass of the
23 # superclass of the mixin (see above)
24 my ($super_meta) = $metaclass->superclasses();
25 my ($super_mixin) = $mixin->superclasses();
26 ($super_meta->isa($super_mixin))
27 || confess "The superclass ($super_meta) must extend a subclass of the " .
28 "superclass of the mixin ($super_mixin)"
29 if defined $super_mixin && defined $super_meta;
31 # check for conflicts here ...
33 $metaclass->has_attribute($_)
34 && confess "Attribute conflict ($_)"
35 foreach $mixin->get_attribute_list;
37 foreach my $method_name ($mixin->get_method_list) {
38 # skip meta, cause everyone has that :)
39 next if $method_name =~ /meta/;
40 $metaclass->has_method($method_name) && confess "Method conflict ($method_name)";
43 # collect all the attributes
44 # and clone them so they can
45 # associate with the new class
46 # add all the attributes in ....
47 foreach my $attr ($mixin->get_attribute_list) {
48 $metaclass->add_attribute(
49 $mixin->get_attribute($attr)->clone()
53 # add all the methods in ....
54 foreach my $method_name ($mixin->get_method_list) {
55 # no need to mess with meta
56 next if $method_name eq 'meta';
57 my $method = $mixin->get_method($method_name);
58 # and ignore accessors, the
59 # attributes take care of that
60 next if blessed($method) && $method->isa('Class::MOP::Attribute::Accessor');
61 $metaclass->alias_method($method_name => $method);
73 Moose::Meta::SafeMixin - A meta-object for safe mixin-style composition
79 This is a meta-object which provides B<safe> mixin-style composition
80 of classes. The key word here is "safe" because we enforce a number
81 of rules about mixing in which prevent some of the instability
82 inherent in other mixin systems. However, it should be noted that we
83 still allow you enough rope with which to shoot yourself in the foot
90 In order to mix classes together, they must inherit from a common
91 superclass. This assures at least some level of similarity between
92 the classes being mixed together, which should result in a more
95 The only exception to this rule is if the class being mixed in has
96 no superclasses at all. In this case we assume the mixin is valid.
100 Since we enforce a common ancestral relationship, we need to be
101 mindful of method and attribute conflicts. The common ancestor
102 increases the potential of method conflicts because it is common
103 for subclasses to override their parents methods. However, it is
104 less common for attributes to be overriden. The way these are
105 resolved is to use a Trait/Role-style conflict mechanism.
107 If two classes are mixed together, any method or attribute conflicts
108 will result in a failure of the mixin and a fatal exception. It is
109 not possible to resolve a method or attribute conflict dynamically.
110 This is because to do so would open the possibility of breaking
111 classes in very subtle and dangerous ways, particularly in the area
112 of method interdependencies. The amount of implementation knowledge
113 which would need to be known by the mixee would (IMO) increase the
114 complexity of the feature exponentially for each class mixed in.
116 However fear not, there is a solution (see below) ...
120 Safe mixin's offer the possibility of CLOS style I<before>, I<after>
121 and I<around> methods with which method conflicts can be resolved.
123 A method, which would normally conflict, but which is labeled with
124 either a I<before>, I<after> or I<around> attribute, will instead be
125 combined with the original method in the way implied by the attribute.
127 The result of this is a generalized event-handling system for classes.
128 Which can be used to create things more specialized, such as plugins
133 =head2 What kinda crack are you on ?!?!?!?
135 This approach may seem crazy, but I am fairly confident that it will
136 work, and that it will not tie your hands unnessecarily. All these
137 features have been used with certain degrees of success in the object
138 systems of other languages, but none (IMO) provided a complete
141 In CLOS, I<before>, I<after> and I<around> methods provide a high
142 degree of flexibility for adding behavior to methods, but do not address
143 any concerns regarding classes since in CLOS, classes and methods are
144 separate components of the system.
146 In Scala, mixins are restricted by their ancestral relationships, which
147 results in a need to have seperate "traits" to get around this restriction.
148 In addition, Scala does not seem to have any means of method conflict
149 resolution for mixins (at least not that I can find).
151 In Perl 6, the role system forces manual disambiguation which (as
152 mentioned above) can cause issues with method interdependecies when
153 composing roles together. This problem will grow exponentially in one
154 direction with each role composed and in the other direction with the
155 number of roles that role itself is composed of. The result is that the
156 complexity of the system becomes unmanagable for all but very simple or
157 very shallow roles. Now, this is not to say that roles are unusable, in
158 fact, this feature (IMO) promotes good useage of roles by keeping them
159 both small and simple. But, the same behaviors cannot be applied to
160 class mixins without hitting these barriers all too quickly.
162 The same too can be said of the original Traits system, with its
163 features for aliasing and exclusion of methods.
165 So after close study of these systems, and in some cases actually
166 implementing said systems, I have come to the see that each on it's
167 own is not robust enough and that combining the best parts of each
168 gives us (what I hope is) a better, safer and saner system.
174 =item B<mixin ($mixin)>
180 Stevan Little E<lt>stevan@iinteractive.comE<gt>
182 =head1 COPYRIGHT AND LICENSE
184 Copyright 2006 by Infinity Interactive, Inc.
186 L<http://www.iinteractive.com>
188 This library is free software; you can redistribute it and/or modify
189 it under the same terms as Perl itself.