1Role::Basic::PhilosophyU(s3eprm)Contributed Perl DocumenRtoaltei:o:nBasic::Philosophy(3pm)
2
3
4

NAME

6       Role::Basic::Philosophy - Why Role::Basic exists.
7

RATIONALE

9       Note: the words "trait" and "role" will be used interchangeably
10       throughout this documentation.
11
12       After years of using roles, your author has found that many people
13       would be happy to use roles but are not willing/comfortable with using
14       Moose.  This module implements roles and nothing else. It does so in a
15       (relatively) simple bit of code.  However, you should be aware that
16       there are some differences between Role::Basic and Moose::Role.
17
18       Moose is a fantastic technology and your author is quite happy with it.
19       He urges you to check it out and perhaps even consider Role::Basic a
20       "stepping-stone" to Moose.  However, after an informal poll with many
21       respondents replying on blogs.perl.org, Twitter, Facebook and private
22       email unanimously saying they wanted this module for roles and not as a
23       stepping-stone to Moose, your author took the liberty of deciding to
24       implement traits in a rather faithful fashion, rather than strictly
25       adhere to the design of Moose::Role.  For areas where we differ,
26       Role::Basic intends to be more restrictive when syntax is the same.
27       This allows an easier migration to Moose::Role when the time is right.
28       Otherwise, Role::Basic will offer a different syntax to avoid
29       confusion.
30

TRAITS

32       As most of you probably know, roles are the Perl implmentation of
33       traits as described in <http://scg.unibe.ch/research/traits/>.  (The
34       name "role" was chosen because "trait" was already used in Perl 6.)  In
35       particular, we direct you to two papers, both of which are easy to
36       read:
37
38       •   <http://scg.unibe.ch/scgbib?_s=tgXJjGrs0380ejY6&_k=Swgdwx_C&query=nathanael+traits+composable+units+ecoop&display=abstract&_n&19>
39
40           The seminal "traits paper" which much of the documentation refers
41           to.
42
43       •   <http://scg.unibe.ch/scgbib?_s=tgXJjGrs0380ejY6&_k=Swgdwx_C&query=traits+the+formal+model&display=abstract&_n&23>
44
45           "Traits: The Formal Model".
46
47           While less well-known, this relatively easy to read paper outlines
48           the mathematical underpinnings of traits and explains several
49           design decisions taken here.
50
51       It is important to refer back to those papers because Role::Basic
52       attempts to implements traits as described in the research, whereas
53       Moose::Role attempts to implement something very similar to traits, but
54       with more of a "Perlish" feel.  This is not intended as a criticism of
55       Moose::Role, but merely an attempt to alert the reader to key
56       differences.
57
58   The Basics
59       Roles are simply bundles of behavior which classes may use. If you have
60       two completely unrelated classes, your code may still require each of
61       them to serialize themselves as JSON even though neither class
62       naturally has anything to do with JSON (for example, "Person" and
63       "Order" classes).  There are a number of approaches to this problem but
64       if you're here I'll skip the explanation and assume that you already
65       understand roles and would like to know why we don't follow the
66       Moose::Role specification.
67
68       As you already probably know, roles allow you to state that your class
69       "DOES" some behaviour, and allows you to exclude or alias bits and
70       pieces of the roles you're including.  The original specification of
71       traits made it clear that this was to be done in such a fashion that no
72       matter how you grouped the traits or in which order you used them, the
73       outcome behavior would be the same. That's why we have subtle but
74       forward-compatible differences with Moose::Role.
75
76       Commutative
77
78       The formal model
79       (<http://scg.unibe.ch/archive/papers/Scha02cTraitsModel.pdf>) states
80       that trait composition must be commutative (section 3.4, proposition
81       1).  This means that:
82
83           (A + B) = (B + A)
84
85       In other words, it should not matter what order you compose the traits
86       in. It is well known that with both inheritance and mixins, this does
87       not hold (making refactoring a dicey proposition at times), but when
88       method modifiers are used with Moose::Role, the same issues arises
89       (from
90       <http://blogs.perl.org/users/ovid/2010/12/rolebasic---when-you-only-want-roles.html>):
91
92           {
93               package Some::Role;
94               use Moose::Role;
95               requires qw(some_method);
96
97               before some_method => sub {
98                   my $self = shift;
99                   $self->some_number( $self->some_number + 2 );
100               };
101           }
102           {
103               package Another::Role;
104               use Moose::Role;
105               requires qw(some_method);
106
107               before some_method => sub {
108                   my $self = shift;
109                   $self->some_number( $self->some_number / 2 );
110               };
111           }
112           {
113               package Some::Class;
114               use Moose;
115               my @roles =
116                 int( rand(2) )
117                 ? qw(Another::Role Some::Role)
118                 : qw(Some::Role Another::Role);
119               with @roles;
120
121               has some_number => ( is => 'rw', isa => 'Num' );
122               sub some_method { print shift->some_number, $/ }
123           }
124           my $o = Some::Class->new( { some_number => 7 } );
125           $o->some_method;
126
127       If you run this code, it might print 4.5, but it might print 5.5. As
128       with mixins and multiple inheritance, you have no way of knowing the
129       exact behaviour which will be exhibited short of running the code. No
130       introspection will help. This is not an issue with Role::Basic because
131       we do not allow method modifiers.  If you think you need them, please
132       consider Moose.
133
134       Associative
135
136       The formal model
137       (<http://scg.unibe.ch/archive/papers/Scha02cTraitsModel.pdf>) states
138       that trait composition must be associative (section 3.4, proposition
139       1).  This means that:
140
141           (A + B) + C = A + (B + C)
142
143       Moose is associative if and only if you do not have multiple methods
144       with the same name.  In Moose, if a role providing method M consumes
145       one other role which also provides method M, we have a conflict:
146
147           package Some::Role;
148           use Moose::Role;
149           sub bar { __PACKAGE__ }
150
151           package Some::Other::Role;
152           use Moose::Role;
153           with 'Some::Role';
154           sub bar { __PACKAGE__ }
155
156           package Some::Class;
157           use Moose;
158           with 'Some::Other::Role';
159
160           package main;
161           my $o = Some::Class->new;
162           print $o->bar;
163
164       However, if the role consumes two or more other roles which provide the
165       same method, we don't have a conflict:
166
167           package Some::Role;
168           use Moose::Role;
169           sub bar { __PACKAGE__ }
170
171           package Some::Other::Role;
172           use Moose::Role;
173           sub bar { __PACKAGE__ }
174
175           package Another::Role;
176           use Moose::Role;
177           with qw(Some::Role Some::Other::Role);
178           sub bar { __PACKAGE__ }
179
180           package Some::Class;
181           use Moose;
182           with 'Another::Role';
183
184           package main;
185           my $o = Some::Class->new;
186           print $o->bar;
187
188       This is because, in Moose, when you have two or more roles consumed,
189       any conflicting methods are excluded and considered to be requirements.
190
191       See "Moose::Role composition edge cases" for more explanation:
192       <http://search.cpan.org/~drolsky/Moose-1.21/lib/Moose/Spec/Role.pod#Composition_Edge_Cases>.
193
194       This makes roles easy to use at times, but it means that the following
195       three groups of roles are not guaranteed to provide the same behavior:
196
197        RoleA does RoleB, RoleC
198        RoleB does RoleA, RoleC
199        RoleC does RoleA, RoleB
200
201       Further, you as a developer have no way of knowing that we have had
202       methods silently excluded without reading all of the code.
203
204       For Role::Basic there are no edge cases. If "RoleA", "RoleB", and
205       "RoleC" all provide method M, you are guaranteed to get a conflict at
206       composition time and must specifically address the problem. This
207       addresses the associative issue because strictly speaking, a trait is
208       merely a bundle of services provided, not its name.  Thus, a trait with
209       its "foo" method excluded is not the same as itself without the "foo"
210       method excluded.
211
212       Benefits of associative and commutative behaviour
213
214       While we recognize that not everyone will be happy with the decisions
215       we have made, we have several benefits here:
216
217       •   We adhere to the formal definition of traits
218
219       •   Ordering and grouping of traits does not alter their behavior
220
221       •   We're forward-compatible with Moose::Role
222

CONCLUSION

224       The primary goal of Role::Basic is to provide traits in a simple and
225       safe manner. We are huge fans of Moose and Moose::Role and suggest that
226       everyone check them out. The decision of Moose::Role to deviate from
227       the "associative" and "commutative" deviations from the original traits
228       model is, in our experience, less likely to occur with roles than with
229       mixins and inhertance, so please do not take this as an indictment, but
230       rather in the spirit of TIMTOWTDI.
231
232
233
234perl v5.38.0                      2023-07-21      Role::Basic::Philosophy(3pm)
Impressum