2 package Class::MOP::Instance;
7 use Scalar::Util 'weaken', 'blessed';
10 $VERSION = eval $VERSION;
11 our $AUTHORITY = 'cpan:STEVAN';
13 use base 'Class::MOP::Object';
15 # make this not a valid method name, to avoid (most) attribute conflicts
16 my $RESERVED_MOP_SLOT = '<<MOP>>';
19 my ($class, @args) = @_;
22 unshift @args, "associated_metaclass";
23 } elsif ( @args >= 2 && blessed($args[0]) && $args[0]->isa("Class::MOP::Class") ) {
25 my ( $meta, @attrs ) = @args;
26 @args = ( associated_metaclass => $meta, attributes => \@attrs );
31 $options{slots} ||= [ map { $_->slots } @{ $options{attributes} || [] } ];
32 $options{slot_hash} = { map { $_ => undef } @{ $options{slots} } }; # FIXME lazy_build
39 my $options = $class->BUILDARGS(@_);
41 # FIXME replace with a proper constructor
42 my $instance = $class->_new(%$options);
44 # FIXME weak_ref => 1,
45 weaken($instance->{'associated_metaclass'});
52 return Class::MOP::Class->initialize($class)->new_object(@_)
53 if $class ne __PACKAGE__;
55 my $params = @_ == 1 ? $_[0] : {@_};
58 # I am not sure that it makes
59 # sense to pass in the meta
60 # The ideal would be to just
61 # pass in the class name, but
62 # that is placing too much of
63 # an assumption on bless(),
64 # which is *probably* a safe
65 # assumption,.. but you can
67 'associated_metaclass' => $params->{associated_metaclass},
68 'attributes' => $params->{attributes},
69 'slots' => $params->{slots},
70 'slot_hash' => $params->{slot_hash},
74 sub _class_name { $_[0]->{_class_name} ||= $_[0]->associated_metaclass->name }
76 sub associated_metaclass { $_[0]{'associated_metaclass'} }
80 bless {}, $self->_class_name;
84 my ($self, $instance) = @_;
85 bless { %$instance }, $self->_class_name;
88 # operations on meta instance
92 return @{$self->{'slots'}};
95 sub get_all_attributes {
97 return @{$self->{attributes}};
101 my ($self, $slot_name) = @_;
102 exists $self->{'slot_hash'}->{$slot_name};
105 # operations on created instances
108 my ($self, $instance, $slot_name) = @_;
109 $instance->{$slot_name};
113 my ($self, $instance, $slot_name, $value) = @_;
114 $instance->{$slot_name} = $value;
117 sub initialize_slot {
118 my ($self, $instance, $slot_name) = @_;
122 sub deinitialize_slot {
123 my ( $self, $instance, $slot_name ) = @_;
124 delete $instance->{$slot_name};
127 sub initialize_all_slots {
128 my ($self, $instance) = @_;
129 foreach my $slot_name ($self->get_all_slots) {
130 $self->initialize_slot($instance, $slot_name);
134 sub deinitialize_all_slots {
135 my ($self, $instance) = @_;
136 foreach my $slot_name ($self->get_all_slots) {
137 $self->deinitialize_slot($instance, $slot_name);
141 sub is_slot_initialized {
142 my ($self, $instance, $slot_name, $value) = @_;
143 exists $instance->{$slot_name};
146 sub weaken_slot_value {
147 my ($self, $instance, $slot_name) = @_;
148 weaken $instance->{$slot_name};
151 sub strengthen_slot_value {
152 my ($self, $instance, $slot_name) = @_;
153 $self->set_slot_value($instance, $slot_name, $self->get_slot_value($instance, $slot_name));
156 sub rebless_instance_structure {
157 my ($self, $instance, $metaclass) = @_;
159 # we use $_[1] here because of t/306_rebless_overload.t regressions on 5.8.8
160 bless $_[1], $metaclass->name;
163 sub is_dependent_on_superclasses {
164 return; # for meta instances that require updates on inherited slot changes
168 my ($self, $instance) = @_;
169 $self->get_slot_value($instance, $RESERVED_MOP_SLOT);
173 my ($self, $instance, $value) = @_;
174 $self->set_slot_value($instance, $RESERVED_MOP_SLOT, $value);
177 sub _clear_mop_slot {
178 my ($self, $instance) = @_;
179 $self->deinitialize_slot($instance, $RESERVED_MOP_SLOT);
182 # inlinable operation snippets
184 sub is_inlinable { 1 }
186 sub inline_create_instance {
187 my ($self, $class_variable) = @_;
188 'bless {} => ' . $class_variable;
191 sub inline_slot_access {
192 my ($self, $instance, $slot_name) = @_;
193 sprintf q[%s->{"%s"}], $instance, quotemeta($slot_name);
196 sub inline_get_is_lvalue { 1 }
198 sub inline_get_slot_value {
199 my ($self, $instance, $slot_name) = @_;
200 $self->inline_slot_access($instance, $slot_name);
203 sub inline_set_slot_value {
204 my ($self, $instance, $slot_name, $value) = @_;
205 $self->inline_slot_access($instance, $slot_name) . " = $value",
208 sub inline_initialize_slot {
209 my ($self, $instance, $slot_name) = @_;
213 sub inline_deinitialize_slot {
214 my ($self, $instance, $slot_name) = @_;
215 "delete " . $self->inline_slot_access($instance, $slot_name);
217 sub inline_is_slot_initialized {
218 my ($self, $instance, $slot_name) = @_;
219 "exists " . $self->inline_slot_access($instance, $slot_name);
222 sub inline_weaken_slot_value {
223 my ($self, $instance, $slot_name) = @_;
224 sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name);
227 sub inline_strengthen_slot_value {
228 my ($self, $instance, $slot_name) = @_;
229 $self->inline_set_slot_value($instance, $slot_name, $self->inline_slot_access($instance, $slot_name));
232 sub inline_rebless_instance_structure {
233 my ($self, $instance, $class_variable) = @_;
234 "bless $instance => $class_variable";
245 Class::MOP::Instance - Instance Meta Object
249 The Instance Protocol controls the creation of object instances, and
250 the storage of attribute values in those instances.
252 Using this API directly in your own code violates encapsulation, and
253 we recommend that you use the appropriate APIs in L<Class::MOP::Class>
254 and L<Class::MOP::Attribute> instead. Those APIs in turn call the
255 methods in this class as appropriate.
257 This class also participates in generating inlined code by providing
258 snippets of code to access an object instance.
262 =head2 Object construction
266 =item B<< Class::MOP::Instance->new(%options) >>
268 This method creates a new meta-instance object.
270 It accepts the following keys in C<%options>:
274 =item * associated_metaclass
276 The L<Class::MOP::Class> object for which instances will be created.
280 An array reference of L<Class::MOP::Attribute> objects. These are the
281 attributes which can be stored in each instance.
287 =head2 Creating and altering instances
291 =item B<< $metainstance->create_instance >>
293 This method returns a reference blessed into the associated
296 The default is to use a hash reference. Subclasses can override this.
298 =item B<< $metainstance->clone_instance($instance) >>
300 Given an instance, this method creates a new object by making
301 I<shallow> clone of the original.
309 =item B<< $metainstance->associated_metaclass >>
311 This returns the L<Class::MOP::Class> object associated with the
312 meta-instance object.
314 =item B<< $metainstance->get_all_slots >>
316 This returns a list of slot names stored in object instances. In
317 almost all cases, slot names correspond directly attribute names.
319 =item B<< $metainstance->is_valid_slot($slot_name) >>
321 This will return true if C<$slot_name> is a valid slot name.
323 =item B<< $metainstance->get_all_attributes >>
325 This returns a list of attributes corresponding to the attributes
326 passed to the constructor.
330 =head2 Operations on Instance Structures
332 It's important to understand that the meta-instance object is a
333 different entity from the actual instances it creates. For this
334 reason, any operations on the C<$instance_structure> always require
335 that the object instance be passed to the method.
339 =item B<< $metainstance->get_slot_value($instance_structure, $slot_name) >>
341 =item B<< $metainstance->set_slot_value($instance_structure, $slot_name, $value) >>
343 =item B<< $metainstance->initialize_slot($instance_structure, $slot_name) >>
345 =item B<< $metainstance->deinitialize_slot($instance_structure, $slot_name) >>
347 =item B<< $metainstance->initialize_all_slots($instance_structure) >>
349 =item B<< $metainstance->deinitialize_all_slots($instance_structure) >>
351 =item B<< $metainstance->is_slot_initialized($instance_structure, $slot_name) >>
353 =item B<< $metainstance->weaken_slot_value($instance_structure, $slot_name) >>
355 =item B<< $metainstance->strengthen_slot_value($instance_structure, $slot_name) >>
357 =item B<< $metainstance->rebless_instance_structure($instance_structure, $new_metaclass) >>
359 The exact details of what each method does should be fairly obvious
360 from the method name.
364 =head2 Inlinable Instance Operations
368 =item B<< $metainstance->is_inlinable >>
370 This is a boolean that indicates whether or not slot access operations
371 can be inlined. By default it is true, but subclasses can override
374 =item B<< $metainstance->inline_create_instance($class_variable) >>
376 This method expects a string that, I<when inlined>, will become a
377 class name. This would literally be something like C<'$class'>, not an
380 It returns a snippet of code that creates a new object for the
381 class. This is something like C< bless {}, $class_name >.
383 =item B<< $metainstance->inline_get_is_lvalue >>
385 Returns whether or not C<inline_get_slot_value> is a valid lvalue. This can be
386 used to do extra optimizations when generating inlined methods.
388 =item B<< $metainstance->inline_slot_access($instance_variable, $slot_name) >>
390 =item B<< $metainstance->inline_get_slot_value($instance_variable, $slot_name) >>
392 =item B<< $metainstance->inline_set_slot_value($instance_variable, $slot_name, $value) >>
394 =item B<< $metainstance->inline_initialize_slot($instance_variable, $slot_name) >>
396 =item B<< $metainstance->inline_deinitialize_slot($instance_variable, $slot_name) >>
398 =item B<< $metainstance->inline_is_slot_initialized($instance_variable, $slot_name) >>
400 =item B<< $metainstance->inline_weaken_slot_value($instance_variable, $slot_name) >>
402 =item B<< $metainstance->inline_strengthen_slot_value($instance_variable, $slot_name) >>
404 These methods all expect two arguments. The first is the name of a
405 variable, than when inlined, will represent the object
406 instance. Typically this will be a literal string like C<'$_[0]'>.
408 The second argument is a slot name.
410 The method returns a snippet of code that, when inlined, performs some
411 operation on the instance.
413 =item B<< $metainstance->inline_rebless_instance_structure($instance_variable, $class_variable) >>
415 This takes the name of a variable that will, when inlined, represent the object
416 instance, and the name of a variable that will represent the class to rebless
417 into, and returns code to rebless an instance into a class.
425 =item B<< Class::MOP::Instance->meta >>
427 This will return a L<Class::MOP::Class> instance for this class.
429 It should also be noted that L<Class::MOP> will actually bootstrap
430 this module by installing a number of attribute meta-objects into its
437 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
439 Stevan Little E<lt>stevan@iinteractive.comE<gt>
441 =head1 COPYRIGHT AND LICENSE
443 Copyright 2006-2010 by Infinity Interactive, Inc.
445 L<http://www.iinteractive.com>
447 This library is free software; you can redistribute it and/or modify
448 it under the same terms as Perl itself.