bunch of stuff
[gitmo/Class-MOP.git] / lib / Class / MOP / SafeMixin.pm
CommitLineData
d3cb0d4a 1
2package Class::MOP::SafeMixin;
3
4use strict;
5use warnings;
6
72c21074 7use Scalar::Util 'blessed';
8use Carp 'confess';
9
d3cb0d4a 10our $VERSION = '0.01';
11
72c21074 12use base 'Class::MOP::Class';
13
14sub mixin {
15 # fetch the metaclass for the
16 # caller and the mixin arg
17 my $metaclass = shift;
de19f115 18 my $mixin = $metaclass->initialize(shift);
72c21074 19
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 must extend a subclass of the superclass of the mixin"
28 if defined $super_mixin && defined $super_meta;
29
30 # collect all the attributes
31 # and clone them so they can
32 # associate with the new class
33 my @attributes = map {
34 $mixin->get_attribute($_)->clone()
35 } $mixin->get_attribute_list;
36
37 my %methods = map {
38 my $method = $mixin->get_method($_);
39 # we want to ignore accessors since
40 # they will be created with the attrs
41 (blessed($method) && $method->isa('Class::MOP::Attribute::Accessor'))
42 ? () : ($_ => $method)
43 } $mixin->get_method_list;
44
45 # NOTE:
46 # I assume that locally defined methods
47 # and attributes get precedence over those
48 # from the mixin.
49
50 # add all the attributes in ....
51 foreach my $attr (@attributes) {
52 $metaclass->add_attribute($attr)
53 unless $metaclass->has_attribute($attr->name);
54 }
55
56 # add all the methods in ....
57 foreach my $method_name (keys %methods) {
58 $metaclass->alias_method($method_name => $methods{$method_name})
59 unless $metaclass->has_method($method_name);
60 }
d3cb0d4a 61}
62
631;
64
65__END__
66
67=pod
68
69=head1 NAME
70
71Class::MOP::SafeMixin - A meta-object for safe mixin-style composition
72
73=head1 SYNOPSIS
74
75=head1 DESCRIPTION
76
77This is a meta-object which provides B<safe> mixin-style composition
78of classes. The key word here is "safe" because we enforce a number
79of rules about mixing in which prevent some of the instability
80inherent in other mixin systems. However, it should be noted that we
81still allow you enough rope with which to shoot yourself in the foot
82if you so desire.
83
84=over 4
85
86=item *
87
88In order to mix classes together, they must inherit from a common
89superclass. This assures at least some level of similarity between
bf5e889b 90the classes being mixed together, which should result in a more
d3cb0d4a 91stable end product.
92
93The only exception to this rule is if the class being mixed in has
94no superclasses at all. In this case we assume the mixin is valid.
95
96=item *
97
98Since we enforce a common ancestral relationship, we need to be
99mindful of method and attribute conflicts. The common ancestor
100increases the potential of method conflicts because it is common
101for subclasses to override their parents methods. However, it is
102less common for attributes to be overriden. The way these are
103resolved is to use a Trait/Role-style conflict mechanism.
104
105If two classes are mixed together, any method or attribute conflicts
106will result in a failure of the mixin and a fatal exception. It is
107not possible to resolve a method or attribute conflict dynamically.
108This is because to do so would open the possibility of breaking
109classes in very subtle and dangerous ways, particularly in the area
110of method interdependencies. The amount of implementation knowledge
111which would need to be known by the mixee would (IMO) increase the
112complexity of the feature exponentially for each class mixed in.
113
114However fear not, there is a solution (see below) ...
115
116=item *
117
118Safe mixin's offer the possibility of CLOS style I<before>, I<after>
119and I<around> methods with which method conflicts can be resolved.
120
121A method, which would normally conflict, but which is labeled with
122either a I<before>, I<after> or I<around> attribute, will instead be
123combined with the original method in the way implied by the attribute.
124
125The result of this is a generalized event-handling system for classes.
126Which can be used to create things more specialized, such as plugins
127and decorators.
128
129=back
130
131=head2 What kinda crack are you on ?!?!?!?
132
133This approach may seem crazy, but I am fairly confident that it will
134work, and that it will not tie your hands unnessecarily. All these
135features have been used with certain degrees of success in the object
136systems of other languages, but none (IMO) provided a complete
137solution.
138
139In CLOS, I<before>, I<after> and I<around> methods provide a high
140degree of flexibility for adding behavior to methods, but do not address
141any concerns regarding classes since in CLOS, classes and methods are
bf5e889b 142separate components of the system.
d3cb0d4a 143
144In Scala, mixins are restricted by their ancestral relationships, which
145results in a need to have seperate "traits" to get around this restriction.
146In addition, Scala does not seem to have any means of method conflict
147resolution for mixins (at least not that I can find).
148
149In Perl 6, the role system forces manual disambiguation which (as
150mentioned above) can cause issues with method interdependecies when
151composing roles together. This problem will grow exponentially in one
152direction with each role composed and in the other direction with the
153number of roles that role itself is composed of. The result is that the
154complexity of the system becomes unmanagable for all but very simple or
155very shallow roles. Now, this is not to say that roles are unusable, in
156fact, this feature (IMO) promotes good useage of roles by keeping them
157both small and simple. But, the same behaviors cannot be applied to
158class mixins without hitting these barriers all too quickly.
159
bf5e889b 160The same too can be said of the original Traits system, with its
d3cb0d4a 161features for aliasing and exclusion of methods.
162
163So after close study of these systems, and in some cases actually
164implementing said systems, I have come to the see that each on it's
165own is not robust enough and that combining the best parts of each
166gives us (what I hope is) a better, safer and saner system.
167
de19f115 168=head1 METHODS
169
170=over 4
171
172=item B<mixin ($mixin)>
173
174=back
175
d3cb0d4a 176=head1 AUTHOR
177
178Stevan Little E<lt>stevan@iinteractive.comE<gt>
179
180=head1 COPYRIGHT AND LICENSE
181
182Copyright 2006 by Infinity Interactive, Inc.
183
184L<http://www.iinteractive.com>
185
186This library is free software; you can redistribute it and/or modify
187it under the same terms as Perl itself.
188
bf5e889b 189=cut