Commit | Line | Data |
686a7f09 |
1 | |
2 | =pod |
3 | |
4 | =head1 NAME |
5 | |
6 | Moose::Cookbook::Snack::Perl5ObjsVsMooseObjs - Short comparison between Perl 5 |
7 | objects and Moose objects |
8 | |
9 | =head1 SYNOPSIS |
10 | |
11 | package Moose::Demo; |
12 | use Moose; # automagically sets 'strict' and 'warnings' |
13 | |
6bf6edf6 |
14 | has 'script_name' => ( is => 'rw', required => 1); |
686a7f09 |
15 | |
16 | package main; |
686a7f09 |
17 | |
18 | # '$0' is the name of this script, set automatically by Perl |
19 | my $demo = Moose::Demo->new( script_name => $0 ); |
20 | |
6bf6edf6 |
21 | print "My name is " . $demo->script_name . "\n"; |
22 | print "I am a " . $demo->meta->name . " type of object\n"; |
686a7f09 |
23 | |
24 | =head1 DESCRIPTION |
25 | |
26 | So what's the big stink about Moose? Perl 5 comes with objects and object |
27 | oriented programming already. Given the above Moose code, what would similar |
28 | code look like in the existing Perl 5 object-oriented style of programming? |
29 | Let's take a look and find out... |
30 | |
31 | =head2 Perl 5 OO Example |
32 | |
33 | # Perl 5 Object, as taught by the 'perltoot' POD page |
34 | package Perl5::Demo; |
35 | use strict; |
36 | use warnings; |
37 | |
38 | |
39 | sub new { |
40 | my $class = shift; |
41 | # assign the rest of the method arguments to a temp hash |
42 | my %args = @_; |
43 | |
44 | # create the object out of a blessed hash reference |
45 | my $self = bless ( {}, ref($class) || $class ); |
46 | # create the script_name attribute |
47 | $self->{script_name} = undef; |
48 | |
49 | # verify that the user passed in the 'script_name' attribute |
50 | if ( exists $args{script_name} ) { |
51 | $self->script_name($args{script_name}); |
3a0c064a |
52 | } |
53 | else { |
6bf6edf6 |
54 | die "ERROR: can't create object without 'script_name' "; |
3a0c064a |
55 | } |
686a7f09 |
56 | |
57 | # return the object reference back to the caller |
58 | return $self; |
3a0c064a |
59 | } |
686a7f09 |
60 | |
61 | sub script_name { |
62 | my $self = shift; |
3a0c064a |
63 | # check for arguments; use the argument |
64 | # if passed in, otherwise return the |
65 | # existing value (if any) |
66 | if (@_) { |
67 | $self->{script_name} = shift; |
68 | } |
686a7f09 |
69 | return $self->{script_name}; |
3a0c064a |
70 | } |
686a7f09 |
71 | |
72 | package main; |
73 | use strict; |
74 | use warnings; |
75 | |
76 | my $demo = Perl5::Demo->new( script_name => $0 ); |
77 | |
6bf6edf6 |
78 | print "My name is " . $demo->script_name . "\n"; |
79 | print "I am a " . ref($demo) . " type of object\n"; |
686a7f09 |
80 | |
81 | Looks more complex, right? Moose does a lot of the labor when working with |
82 | Perl objects, so that you don't have to. What are some of the specific |
83 | differences between Moose and Perl 5 Objects? |
84 | |
85 | =head3 Difference #1 - declaration of object attributes |
86 | |
87 | Both the Moose and Perl 5 objects have one attribute, C<script_name>. It's a |
88 | good programming practice to always validate user input, so we have the Perl 5 |
89 | object check to make sure that the user passes in the C<script_name> attribute |
90 | to it when the object is created. The Moose object automatically checks this |
91 | for us when we set C<required =E<gt> 1> in the C<has> function for the Moose |
92 | object. |
93 | |
94 | In more advanced Moose usage, you can use something called 'type constraints' |
95 | when creating your Moose objects. Type constraints are used to validate what |
96 | the user passes in when setting Moose object attributes. If the user passes |
97 | in a type of data that Moose is not expecting, then the type constraints in |
98 | Moose (specifically, the L<Moose::Util::TypeConstraint> module) will let the |
99 | user know this in no uncertain terms. Type constraints in Moose can be as |
100 | simple as strings or numbers, or as complex as other Moose objects. |
101 | |
102 | =head3 Difference #2 - strict and warning pragmas |
103 | |
104 | Moose sets the 'strict' and 'warnings' pragmas for you automatically. We have |
105 | to do this for ourselves in the Perl 5 example. |
106 | |
107 | =head3 Difference #3 - Determining an object's class name |
108 | |
109 | The C<ref()> function in Perl 5 is how you determine an object's class name. |
6bf6edf6 |
110 | The proper way to do this with Moose is C<$object-E<gt>meta-E<gt>name>; |
686a7f09 |
111 | |
112 | # an object's class name in Perl 5 OO |
6bf6edf6 |
113 | print "I am a " . ref($demo) . " type of object\n"; |
686a7f09 |
114 | |
115 | # an object's class name in Moose |
6bf6edf6 |
116 | print "I am a " . $demo->meta->name . " type of object\n"; |
686a7f09 |
117 | |
1d996f46 |
118 | Moose builds on C<Class::MOP> to provide a rich introspection API that |
119 | goes way beyond just getting the class name. Check out the |
120 | C<Class::MOP> documentation for more details. |
121 | |
686a7f09 |
122 | =head3 Difference #4 - Assigning values to Moose object attributes |
123 | |
124 | When you wish to assign a value directly to an object attribute for a Perl 5 |
125 | object, you can either create an object method that handles the value for you; |
126 | |
127 | package Perl5Object; |
6bf6edf6 |
128 | sub set_x { # some code here that sets 'x' } |
686a7f09 |
129 | package main; |
130 | # later on... |
131 | $self->set_x(0); |
132 | |
133 | or you can assign the value directly to the Perl 5 object attribute like this: |
134 | |
135 | $self->{x} = 0; |
136 | |
137 | Moose creates object methods for handling attributes for you, as long as you |
138 | specified C<is =E<gt> rw> for each C<has> statement inside the object |
139 | declaration. This is mentioned in L<Moose::Cookbook::WTF>, in the section |
140 | labeld B<Accessors>, but briefly: |
141 | |
142 | package MooseObject; |
143 | has 'x' => (is => 'rw'); |
144 | package main; |
145 | # later on... |
146 | $self->x(0); |
147 | |
1d996f46 |
148 | The syntax shown for the Perl 5 object (C<$self-E<gt>{x} = 0>) will |
149 | also work on the Moose object, as Moose objects are, by default, |
150 | blessed hashes just like the average Perl object is. However, if you |
151 | access the object's hash reference directly via the latter syntax you |
152 | will have several problems. |
686a7f09 |
153 | |
defceb0c |
154 | First, Moose will no longer be able to enforce attribute constraints, |
1d996f46 |
155 | such as read-only or type constraints. Second, you've broken that |
156 | object's encapsulation, and encapsulation is one of the reasons you |
157 | want to use objects in the first place, right? |
686a7f09 |
158 | |
159 | =head1 SEE ALSO |
160 | |
161 | =over 4 |
162 | |
163 | =item L<Moose::Cookbook::Recipe1> - The 'Point' object example |
164 | |
165 | =item L<Moose::Util::TypeConstraints> - Type constraints that Moose can use |
3a0c064a |
166 | and the tools to extend them or create your own. |
686a7f09 |
167 | |
168 | =item L<Moose::Cookbook::WTF> - For when things go wrong with Moose |
169 | |
170 | =back |
171 | |
172 | =head1 AUTHOR |
173 | |
174 | Brian Manning <elspicyjack at gmail dot com> |
175 | |
176 | =head1 COPYRIGHT AND LICENSE |
177 | |
3a0c064a |
178 | Copyright 2006-2008 by Infinity Interactive, Inc. |
686a7f09 |
179 | |
3a0c064a |
180 | L<http://www.iinteractive.com> |
181 | |
182 | This library is free software; you can redistribute it and/or modify |
686a7f09 |
183 | it under the same terms as Perl itself. |
184 | |
185 | =cut |