microoptimize Class::MOP::Class::initialize since it's called so often
[gitmo/Class-MOP.git] / lib / Class / MOP / Instance.pm
CommitLineData
24869f62 1
2package Class::MOP::Instance;
3
4use strict;
5use warnings;
6
fa16e528 7use Scalar::Util 'weaken', 'blessed';
24869f62 8
2e5c1a3f 9our $VERSION = '0.65';
f0480c45 10our $AUTHORITY = 'cpan:STEVAN';
24869f62 11
d7b2249e 12use base 'Class::MOP::Object';
24869f62 13
63d08a9e 14sub BUILDARGS {
d43737b3 15 my ($class, @args) = @_;
16
17 if ( @args == 1 ) {
63d08a9e 18 unshift @args, "associated_metaclass";
d43737b3 19 } elsif ( @args >= 2 && blessed($args[0]) && $args[0]->isa("Class::MOP::Class") ) {
20 # compat mode
21 my ( $meta, @attrs ) = @args;
63d08a9e 22 @args = ( associated_metaclass => $meta, attributes => \@attrs );
d43737b3 23 }
24
25 my %options = @args;
7c7fd869 26 # FIXME lazy_build
d43737b3 27 $options{slots} ||= [ map { $_->slots } @{ $options{attributes} || [] } ];
63d08a9e 28 $options{slot_hash} = { map { $_ => undef } @{ $options{slots} } }; # FIXME lazy_build
29
30 return \%options;
31}
32
33sub new {
34 my $class = shift;
35 my $options = $class->BUILDARGS(@_);
d43737b3 36
37 # FIXME replace with a proper constructor
c23184fc 38 my $instance = bless {
fc3ddd1d 39 # NOTE:
40 # I am not sure that it makes
41 # sense to pass in the meta
8d2d4c67 42 # The ideal would be to just
43 # pass in the class name, but
44 # that is placing too much of
45 # an assumption on bless(),
fc3ddd1d 46 # which is *probably* a safe
8d2d4c67 47 # assumption,.. but you can
fc3ddd1d 48 # never tell <:)
63d08a9e 49 'associated_metaclass' => $options->{associated_metaclass},
32bfc810 50 'attributes' => $options->{attributes},
51 'slots' => $options->{slots},
52 'slot_hash' => $options->{slot_hash},
8d2d4c67 53 } => $class;
54
d43737b3 55 # FIXME weak_ref => 1,
63d08a9e 56 weaken($instance->{'associated_metaclass'});
8d2d4c67 57
c23184fc 58 return $instance;
24869f62 59}
60
63d08a9e 61sub associated_metaclass { (shift)->{'associated_metaclass'} }
c23184fc 62
49c93440 63sub create_instance {
64 my $self = shift;
65 $self->bless_instance_structure({});
2d711cc8 66}
67
49c93440 68sub bless_instance_structure {
69 my ($self, $instance_structure) = @_;
c23184fc 70 bless $instance_structure, $self->associated_metaclass->name;
2d711cc8 71}
72
f7259199 73sub clone_instance {
74 my ($self, $instance) = @_;
75 $self->bless_instance_structure({ %$instance });
76}
77
2d711cc8 78# operations on meta instance
79
eb49acde 80sub get_all_slots {
81 my $self = shift;
7c7fd869 82 return @{$self->{'slots'}};
f7259199 83}
84
85sub is_valid_slot {
86 my ($self, $slot_name) = @_;
7c7fd869 87 exists $self->{'slot_hash'}->{$slot_name};
839ea973 88}
89
2d711cc8 90# operations on created instances
91
839ea973 92sub get_slot_value {
2bab2be6 93 my ($self, $instance, $slot_name) = @_;
230472a7 94 $instance->{$slot_name};
839ea973 95}
96
2bab2be6 97sub set_slot_value {
98 my ($self, $instance, $slot_name, $value) = @_;
99 $instance->{$slot_name} = $value;
100}
101
2d711cc8 102sub initialize_slot {
49c93440 103 my ($self, $instance, $slot_name) = @_;
a007159d 104 return;
2d711cc8 105}
106
7d28758b 107sub deinitialize_slot {
108 my ( $self, $instance, $slot_name ) = @_;
109 delete $instance->{$slot_name};
110}
111
c174112e 112sub initialize_all_slots {
113 my ($self, $instance) = @_;
114 foreach my $slot_name ($self->get_all_slots) {
115 $self->initialize_slot($instance, $slot_name);
116 }
117}
118
7d28758b 119sub deinitialize_all_slots {
120 my ($self, $instance) = @_;
121 foreach my $slot_name ($self->get_all_slots) {
122 $self->deinitialize_slot($instance, $slot_name);
123 }
124}
125
49c93440 126sub is_slot_initialized {
127 my ($self, $instance, $slot_name, $value) = @_;
230472a7 128 exists $instance->{$slot_name};
2bab2be6 129}
839ea973 130
5582521c 131sub weaken_slot_value {
69e3ab0a 132 my ($self, $instance, $slot_name) = @_;
133 weaken $instance->{$slot_name};
5582521c 134}
135
136sub strengthen_slot_value {
69e3ab0a 137 my ($self, $instance, $slot_name) = @_;
138 $self->set_slot_value($instance, $slot_name, $self->get_slot_value($instance, $slot_name));
5582521c 139}
140
3d9e4646 141sub rebless_instance_structure {
142 my ($self, $instance, $metaclass) = @_;
143 bless $instance, $metaclass->name;
144}
145
da5680be 146sub is_dependent_on_superclasses {
147 return; # for meta instances that require updates on inherited slot changes
148}
149
ee7c0467 150# inlinable operation snippets
151
c0cbf4d9 152sub is_inlinable { 1 }
153
154sub inline_create_instance {
155 my ($self, $class_variable) = @_;
156 'bless {} => ' . $class_variable;
157}
158
ee7c0467 159sub inline_slot_access {
160 my ($self, $instance, $slot_name) = @_;
161 sprintf "%s->{%s}", $instance, $slot_name;
162}
163
164sub inline_get_slot_value {
165 my ($self, $instance, $slot_name) = @_;
230472a7 166 $self->inline_slot_access($instance, $slot_name);
ee7c0467 167}
168
169sub inline_set_slot_value {
170 my ($self, $instance, $slot_name, $value) = @_;
8d2d4c67 171 $self->inline_slot_access($instance, $slot_name) . " = $value",
ee7c0467 172}
173
174sub inline_initialize_slot {
175 my ($self, $instance, $slot_name) = @_;
a007159d 176 return '';
ee7c0467 177}
178
7d28758b 179sub inline_deinitialize_slot {
180 my ($self, $instance, $slot_name) = @_;
181 "delete " . $self->inline_slot_access($instance, $slot_name);
182}
ee7c0467 183sub inline_is_slot_initialized {
184 my ($self, $instance, $slot_name) = @_;
230472a7 185 "exists " . $self->inline_slot_access($instance, $slot_name);
ee7c0467 186}
187
188sub inline_weaken_slot_value {
189 my ($self, $instance, $slot_name) = @_;
190 sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name);
191}
192
193sub inline_strengthen_slot_value {
194 my ($self, $instance, $slot_name) = @_;
195 $self->inline_set_slot_value($instance, $slot_name, $self->inline_slot_access($instance, $slot_name));
196}
197
24869f62 1981;
199
200__END__
201
202=pod
203
8d2d4c67 204=head1 NAME
24869f62 205
206Class::MOP::Instance - Instance Meta Object
207
24869f62 208=head1 DESCRIPTION
209
bc9e7815 210The meta instance is used by attributes for low level storage.
211
212Using this API generally violates attribute encapsulation and is not
98bf345b 213recommended, instead look at L<Class::MOP::Attribute/get_value>,
214L<Class::MOP::Attribute/set_value> for the recommended way to fiddle with
215attribute values in a generic way, independent of how/whether accessors have
bc9e7815 216been defined. Accessors can be found using L<Class::MOP::Class/get_attribute>.
9fa4d0b4 217
8d2d4c67 218This may seem like over-abstraction, but by abstracting
219this process into a sub-protocol we make it possible to
220easily switch the details of how an object's instance is
221stored with minimal impact. In most cases just subclassing
222this class will be all you need to do (see the examples;
223F<examples/ArrayBasedStorage.pod> and
1becdfcc 224F<examples/InsideOutClass.pod> for details).
9fa4d0b4 225
24869f62 226=head1 METHODS
227
228=over 4
229
63d08a9e 230=item B<new %args>
9fa4d0b4 231
8d2d4c67 232Creates a new instance meta-object and gathers all the slots from
9fa4d0b4 233the list of C<@attrs> given.
234
63d08a9e 235=item B<BUILDARGS>
236
237Processes arguments for compatibility.
238
9fa4d0b4 239=item B<meta>
240
63d08a9e 241Returns the metaclass of L<Class::MOP::Instance>.
9fa4d0b4 242
243=back
244
245=head2 Creation of Instances
246
247=over 4
24869f62 248
58287a97 249=item B<create_instance>
250
8d2d4c67 251This creates the appropriate structure needed for the instance and
9fa4d0b4 252then calls C<bless_instance_structure> to bless it into the class.
0e76a376 253
9fa4d0b4 254=item B<bless_instance_structure ($instance_structure)>
839ea973 255
9fa4d0b4 256This does just exactly what it says it does.
0e76a376 257
f7259199 258=item B<clone_instance ($instance_structure)>
259
127d39a7 260This too does just exactly what it says it does.
261
9fa4d0b4 262=back
839ea973 263
98bf345b 264=head2 Introspection
58287a97 265
8d2d4c67 266NOTE: There might be more methods added to this part of the API,
9fa4d0b4 267we will add then when we need them basically.
58287a97 268
9fa4d0b4 269=over 4
270
c23184fc 271=item B<associated_metaclass>
272
127d39a7 273This returns the metaclass associated with this instance.
274
9fa4d0b4 275=item B<get_all_slots>
276
8d2d4c67 277This will return the current list of slots based on what was
9fa4d0b4 278given to this object in C<new>.
58287a97 279
f7259199 280=item B<is_valid_slot ($slot_name)>
281
127d39a7 282This will return true if C<$slot_name> is a valid slot name.
283
da5680be 284=item B<is_dependent_on_superclasses>
285
286This method returns true when the meta instance must be recreated on any
287superclass changes.
288
289Defaults to false.
290
24869f62 291=back
292
9fa4d0b4 293=head2 Operations on Instance Structures
294
8d2d4c67 295An important distinction of this sub-protocol is that the
296instance meta-object is a different entity from the actual
297instance it creates. For this reason, any actions on slots
9fa4d0b4 298require that the C<$instance_structure> is passed into them.
24869f62 299
127d39a7 300The names of these methods pretty much explain exactly
301what they do, if that is not enough then I suggest reading
302the source, it is very straightfoward.
303
24869f62 304=over 4
305
9fa4d0b4 306=item B<get_slot_value ($instance_structure, $slot_name)>
24869f62 307
9fa4d0b4 308=item B<set_slot_value ($instance_structure, $slot_name, $value)>
309
310=item B<initialize_slot ($instance_structure, $slot_name)>
311
7d28758b 312=item B<deinitialize_slot ($instance_structure, $slot_name)>
313
9fa4d0b4 314=item B<initialize_all_slots ($instance_structure)>
315
7d28758b 316=item B<deinitialize_all_slots ($instance_structure)>
317
9fa4d0b4 318=item B<is_slot_initialized ($instance_structure, $slot_name)>
24869f62 319
ee7c0467 320=item B<weaken_slot_value ($instance_structure, $slot_name)>
321
322=item B<strengthen_slot_value ($instance_structure, $slot_name)>
323
5fdf066d 324=item B<rebless_instance_structure ($instance_structure, $new_metaclass)>
325
ee7c0467 326=back
327
328=head2 Inlineable Instance Operations
329
330=over 4
331
c0cbf4d9 332=item B<is_inlinable>
333
8d2d4c67 334Each meta-instance should override this method to tell Class::MOP if it's
127d39a7 335possible to inline the slot access. This is currently only used by
336L<Class::MOP::Immutable> when performing optimizations.
c0cbf4d9 337
495af518 338=item B<inline_create_instance>
339
ee7c0467 340=item B<inline_slot_access ($instance_structure, $slot_name)>
341
342=item B<inline_get_slot_value ($instance_structure, $slot_name)>
343
344=item B<inline_set_slot_value ($instance_structure, $slot_name, $value)>
345
346=item B<inline_initialize_slot ($instance_structure, $slot_name)>
347
7d28758b 348=item B<inline_deinitialize_slot ($instance_structure, $slot_name)>
349
ee7c0467 350=item B<inline_is_slot_initialized ($instance_structure, $slot_name)>
5582521c 351
ee7c0467 352=item B<inline_weaken_slot_value ($instance_structure, $slot_name)>
5582521c 353
ee7c0467 354=item B<inline_strengthen_slot_value ($instance_structure, $slot_name)>
5582521c 355
24869f62 356=back
357
1a09d9cc 358=head1 AUTHORS
24869f62 359
9fa4d0b4 360Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
361
24869f62 362Stevan Little E<lt>stevan@iinteractive.comE<gt>
363
364=head1 COPYRIGHT AND LICENSE
365
69e3ab0a 366Copyright 2006-2008 by Infinity Interactive, Inc.
24869f62 367
368L<http://www.iinteractive.com>
369
370This library is free software; you can redistribute it and/or modify
8d2d4c67 371it under the same terms as Perl itself.
24869f62 372
84ef30d1 373=cut
5582521c 374