Commit | Line | Data |
d3cb0d4a |
1 | |
2 | package Class::MOP::SafeMixin; |
3 | |
4 | use strict; |
5 | use warnings; |
6 | |
7 | our $VERSION = '0.01'; |
8 | |
9 | sub meta { |
10 | require Class::MOP::Class; |
11 | Class::MOP::Class->initialize(blessed($_[0]) || $_[0]); |
12 | } |
13 | |
14 | 1; |
15 | |
16 | __END__ |
17 | |
18 | =pod |
19 | |
20 | =head1 NAME |
21 | |
22 | Class::MOP::SafeMixin - A meta-object for safe mixin-style composition |
23 | |
24 | =head1 SYNOPSIS |
25 | |
26 | =head1 DESCRIPTION |
27 | |
28 | This is a meta-object which provides B<safe> mixin-style composition |
29 | of classes. The key word here is "safe" because we enforce a number |
30 | of rules about mixing in which prevent some of the instability |
31 | inherent in other mixin systems. However, it should be noted that we |
32 | still allow you enough rope with which to shoot yourself in the foot |
33 | if you so desire. |
34 | |
35 | =over 4 |
36 | |
37 | =item * |
38 | |
39 | In order to mix classes together, they must inherit from a common |
40 | superclass. This assures at least some level of similarity between |
41 | the classes being mixed together, which should results in a more |
42 | stable end product. |
43 | |
44 | The only exception to this rule is if the class being mixed in has |
45 | no superclasses at all. In this case we assume the mixin is valid. |
46 | |
47 | =item * |
48 | |
49 | Since we enforce a common ancestral relationship, we need to be |
50 | mindful of method and attribute conflicts. The common ancestor |
51 | increases the potential of method conflicts because it is common |
52 | for subclasses to override their parents methods. However, it is |
53 | less common for attributes to be overriden. The way these are |
54 | resolved is to use a Trait/Role-style conflict mechanism. |
55 | |
56 | If two classes are mixed together, any method or attribute conflicts |
57 | will result in a failure of the mixin and a fatal exception. It is |
58 | not possible to resolve a method or attribute conflict dynamically. |
59 | This is because to do so would open the possibility of breaking |
60 | classes in very subtle and dangerous ways, particularly in the area |
61 | of method interdependencies. The amount of implementation knowledge |
62 | which would need to be known by the mixee would (IMO) increase the |
63 | complexity of the feature exponentially for each class mixed in. |
64 | |
65 | However fear not, there is a solution (see below) ... |
66 | |
67 | =item * |
68 | |
69 | Safe mixin's offer the possibility of CLOS style I<before>, I<after> |
70 | and I<around> methods with which method conflicts can be resolved. |
71 | |
72 | A method, which would normally conflict, but which is labeled with |
73 | either a I<before>, I<after> or I<around> attribute, will instead be |
74 | combined with the original method in the way implied by the attribute. |
75 | |
76 | The result of this is a generalized event-handling system for classes. |
77 | Which can be used to create things more specialized, such as plugins |
78 | and decorators. |
79 | |
80 | =back |
81 | |
82 | =head2 What kinda crack are you on ?!?!?!? |
83 | |
84 | This approach may seem crazy, but I am fairly confident that it will |
85 | work, and that it will not tie your hands unnessecarily. All these |
86 | features have been used with certain degrees of success in the object |
87 | systems of other languages, but none (IMO) provided a complete |
88 | solution. |
89 | |
90 | In CLOS, I<before>, I<after> and I<around> methods provide a high |
91 | degree of flexibility for adding behavior to methods, but do not address |
92 | any concerns regarding classes since in CLOS, classes and methods are |
93 | seperate components of the system. |
94 | |
95 | In Scala, mixins are restricted by their ancestral relationships, which |
96 | results in a need to have seperate "traits" to get around this restriction. |
97 | In addition, Scala does not seem to have any means of method conflict |
98 | resolution for mixins (at least not that I can find). |
99 | |
100 | In Perl 6, the role system forces manual disambiguation which (as |
101 | mentioned above) can cause issues with method interdependecies when |
102 | composing roles together. This problem will grow exponentially in one |
103 | direction with each role composed and in the other direction with the |
104 | number of roles that role itself is composed of. The result is that the |
105 | complexity of the system becomes unmanagable for all but very simple or |
106 | very shallow roles. Now, this is not to say that roles are unusable, in |
107 | fact, this feature (IMO) promotes good useage of roles by keeping them |
108 | both small and simple. But, the same behaviors cannot be applied to |
109 | class mixins without hitting these barriers all too quickly. |
110 | |
111 | The same too can be said of the original Triats system, with it's |
112 | features for aliasing and exclusion of methods. |
113 | |
114 | So after close study of these systems, and in some cases actually |
115 | implementing said systems, I have come to the see that each on it's |
116 | own is not robust enough and that combining the best parts of each |
117 | gives us (what I hope is) a better, safer and saner system. |
118 | |
119 | =head1 AUTHOR |
120 | |
121 | Stevan Little E<lt>stevan@iinteractive.comE<gt> |
122 | |
123 | =head1 COPYRIGHT AND LICENSE |
124 | |
125 | Copyright 2006 by Infinity Interactive, Inc. |
126 | |
127 | L<http://www.iinteractive.com> |
128 | |
129 | This library is free software; you can redistribute it and/or modify |
130 | it under the same terms as Perl itself. |
131 | |
132 | =cut |