2 package Class::MOP::Instance;
7 use Scalar::Util 'weaken', 'blessed';
9 our $AUTHORITY = 'cpan:STEVAN';
11 use base 'Class::MOP::Object';
13 # make this not a valid method name, to avoid (most) attribute conflicts
14 my $RESERVED_MOP_SLOT = '<<MOP>>';
17 my ($class, @args) = @_;
20 unshift @args, "associated_metaclass";
21 } elsif ( @args >= 2 && blessed($args[0]) && $args[0]->isa("Class::MOP::Class") ) {
23 my ( $meta, @attrs ) = @args;
24 @args = ( associated_metaclass => $meta, attributes => \@attrs );
29 $options{slots} ||= [ map { $_->slots } @{ $options{attributes} || [] } ];
30 $options{slot_hash} = { map { $_ => undef } @{ $options{slots} } }; # FIXME lazy_build
37 my $options = $class->BUILDARGS(@_);
39 # FIXME replace with a proper constructor
40 my $instance = $class->_new(%$options);
42 # FIXME weak_ref => 1,
43 weaken($instance->{'associated_metaclass'});
50 return Class::MOP::Class->initialize($class)->new_object(@_)
51 if $class ne __PACKAGE__;
53 my $params = @_ == 1 ? $_[0] : {@_};
56 # I am not sure that it makes
57 # sense to pass in the meta
58 # The ideal would be to just
59 # pass in the class name, but
60 # that is placing too much of
61 # an assumption on bless(),
62 # which is *probably* a safe
63 # assumption,.. but you can
65 'associated_metaclass' => $params->{associated_metaclass},
66 'attributes' => $params->{attributes},
67 'slots' => $params->{slots},
68 'slot_hash' => $params->{slot_hash},
72 sub _class_name { $_[0]->{_class_name} ||= $_[0]->associated_metaclass->name }
76 bless {}, $self->_class_name;
80 my ($self, $instance) = @_;
81 bless { %$instance }, $self->_class_name;
84 # operations on meta instance
88 return @{$self->{'slots'}};
91 sub get_all_attributes {
93 return @{$self->{attributes}};
97 my ($self, $slot_name) = @_;
98 exists $self->{'slot_hash'}->{$slot_name};
101 # operations on created instances
104 my ($self, $instance, $slot_name) = @_;
105 $instance->{$slot_name};
109 my ($self, $instance, $slot_name, $value) = @_;
110 $instance->{$slot_name} = $value;
113 sub initialize_slot {
114 my ($self, $instance, $slot_name) = @_;
118 sub deinitialize_slot {
119 my ( $self, $instance, $slot_name ) = @_;
120 delete $instance->{$slot_name};
123 sub initialize_all_slots {
124 my ($self, $instance) = @_;
125 foreach my $slot_name ($self->get_all_slots) {
126 $self->initialize_slot($instance, $slot_name);
130 sub deinitialize_all_slots {
131 my ($self, $instance) = @_;
132 foreach my $slot_name ($self->get_all_slots) {
133 $self->deinitialize_slot($instance, $slot_name);
137 sub is_slot_initialized {
138 my ($self, $instance, $slot_name, $value) = @_;
139 exists $instance->{$slot_name};
142 sub weaken_slot_value {
143 my ($self, $instance, $slot_name) = @_;
144 weaken $instance->{$slot_name};
147 sub strengthen_slot_value {
148 my ($self, $instance, $slot_name) = @_;
149 $self->set_slot_value($instance, $slot_name, $self->get_slot_value($instance, $slot_name));
152 sub rebless_instance_structure {
153 my ($self, $instance, $metaclass) = @_;
155 # we use $_[1] here because of t/306_rebless_overload.t regressions on 5.8.8
156 bless $_[1], $metaclass->name;
159 sub is_dependent_on_superclasses {
160 return; # for meta instances that require updates on inherited slot changes
164 my ($self, $instance) = @_;
165 $self->get_slot_value($instance, $RESERVED_MOP_SLOT);
169 my ($self, $instance, $value) = @_;
170 $self->set_slot_value($instance, $RESERVED_MOP_SLOT, $value);
173 sub _clear_mop_slot {
174 my ($self, $instance) = @_;
175 $self->deinitialize_slot($instance, $RESERVED_MOP_SLOT);
178 # inlinable operation snippets
180 sub is_inlinable { 1 }
182 sub inline_create_instance {
183 my ($self, $class_variable) = @_;
184 'bless {} => ' . $class_variable;
187 sub inline_slot_access {
188 my ($self, $instance, $slot_name) = @_;
189 sprintf q[%s->{"%s"}], $instance, quotemeta($slot_name);
192 sub inline_get_is_lvalue { 1 }
194 sub inline_get_slot_value {
195 my ($self, $instance, $slot_name) = @_;
196 $self->inline_slot_access($instance, $slot_name);
199 sub inline_set_slot_value {
200 my ($self, $instance, $slot_name, $value) = @_;
201 $self->inline_slot_access($instance, $slot_name) . " = $value",
204 sub inline_initialize_slot {
205 my ($self, $instance, $slot_name) = @_;
209 sub inline_deinitialize_slot {
210 my ($self, $instance, $slot_name) = @_;
211 "delete " . $self->inline_slot_access($instance, $slot_name);
213 sub inline_is_slot_initialized {
214 my ($self, $instance, $slot_name) = @_;
215 "exists " . $self->inline_slot_access($instance, $slot_name);
218 sub inline_weaken_slot_value {
219 my ($self, $instance, $slot_name) = @_;
220 sprintf "Scalar::Util::weaken( %s )", $self->inline_slot_access($instance, $slot_name);
223 sub inline_strengthen_slot_value {
224 my ($self, $instance, $slot_name) = @_;
225 $self->inline_set_slot_value($instance, $slot_name, $self->inline_slot_access($instance, $slot_name));
228 sub inline_rebless_instance_structure {
229 my ($self, $instance, $class_variable) = @_;
230 "bless $instance => $class_variable";
233 sub _inline_get_mop_slot {
234 my ($self, $instance) = @_;
235 $self->inline_get_slot_value($instance, $RESERVED_MOP_SLOT);
238 sub _inline_set_mop_slot {
239 my ($self, $instance, $value) = @_;
240 $self->inline_set_slot_value($instance, $RESERVED_MOP_SLOT, $value);
243 sub _inline_clear_mop_slot {
244 my ($self, $instance) = @_;
245 $self->inline_deinitialize_slot($instance, $RESERVED_MOP_SLOT);
250 # ABSTRACT: Instance Meta Object
258 The Instance Protocol controls the creation of object instances, and
259 the storage of attribute values in those instances.
261 Using this API directly in your own code violates encapsulation, and
262 we recommend that you use the appropriate APIs in L<Class::MOP::Class>
263 and L<Class::MOP::Attribute> instead. Those APIs in turn call the
264 methods in this class as appropriate.
266 This class also participates in generating inlined code by providing
267 snippets of code to access an object instance.
271 =head2 Object construction
275 =item B<< Class::MOP::Instance->new(%options) >>
277 This method creates a new meta-instance object.
279 It accepts the following keys in C<%options>:
283 =item * associated_metaclass
285 The L<Class::MOP::Class> object for which instances will be created.
289 An array reference of L<Class::MOP::Attribute> objects. These are the
290 attributes which can be stored in each instance.
296 =head2 Creating and altering instances
300 =item B<< $metainstance->create_instance >>
302 This method returns a reference blessed into the associated
305 The default is to use a hash reference. Subclasses can override this.
307 =item B<< $metainstance->clone_instance($instance) >>
309 Given an instance, this method creates a new object by making
310 I<shallow> clone of the original.
318 =item B<< $metainstance->associated_metaclass >>
320 This returns the L<Class::MOP::Class> object associated with the
321 meta-instance object.
323 =item B<< $metainstance->get_all_slots >>
325 This returns a list of slot names stored in object instances. In
326 almost all cases, slot names correspond directly attribute names.
328 =item B<< $metainstance->is_valid_slot($slot_name) >>
330 This will return true if C<$slot_name> is a valid slot name.
332 =item B<< $metainstance->get_all_attributes >>
334 This returns a list of attributes corresponding to the attributes
335 passed to the constructor.
339 =head2 Operations on Instance Structures
341 It's important to understand that the meta-instance object is a
342 different entity from the actual instances it creates. For this
343 reason, any operations on the C<$instance_structure> always require
344 that the object instance be passed to the method.
348 =item B<< $metainstance->get_slot_value($instance_structure, $slot_name) >>
350 =item B<< $metainstance->set_slot_value($instance_structure, $slot_name, $value) >>
352 =item B<< $metainstance->initialize_slot($instance_structure, $slot_name) >>
354 =item B<< $metainstance->deinitialize_slot($instance_structure, $slot_name) >>
356 =item B<< $metainstance->initialize_all_slots($instance_structure) >>
358 =item B<< $metainstance->deinitialize_all_slots($instance_structure) >>
360 =item B<< $metainstance->is_slot_initialized($instance_structure, $slot_name) >>
362 =item B<< $metainstance->weaken_slot_value($instance_structure, $slot_name) >>
364 =item B<< $metainstance->strengthen_slot_value($instance_structure, $slot_name) >>
366 =item B<< $metainstance->rebless_instance_structure($instance_structure, $new_metaclass) >>
368 The exact details of what each method does should be fairly obvious
369 from the method name.
373 =head2 Inlinable Instance Operations
377 =item B<< $metainstance->is_inlinable >>
379 This is a boolean that indicates whether or not slot access operations
380 can be inlined. By default it is true, but subclasses can override
383 =item B<< $metainstance->inline_create_instance($class_variable) >>
385 This method expects a string that, I<when inlined>, will become a
386 class name. This would literally be something like C<'$class'>, not an
389 It returns a snippet of code that creates a new object for the
390 class. This is something like C< bless {}, $class_name >.
392 =item B<< $metainstance->inline_get_is_lvalue >>
394 Returns whether or not C<inline_get_slot_value> is a valid lvalue. This can be
395 used to do extra optimizations when generating inlined methods.
397 =item B<< $metainstance->inline_slot_access($instance_variable, $slot_name) >>
399 =item B<< $metainstance->inline_get_slot_value($instance_variable, $slot_name) >>
401 =item B<< $metainstance->inline_set_slot_value($instance_variable, $slot_name, $value) >>
403 =item B<< $metainstance->inline_initialize_slot($instance_variable, $slot_name) >>
405 =item B<< $metainstance->inline_deinitialize_slot($instance_variable, $slot_name) >>
407 =item B<< $metainstance->inline_is_slot_initialized($instance_variable, $slot_name) >>
409 =item B<< $metainstance->inline_weaken_slot_value($instance_variable, $slot_name) >>
411 =item B<< $metainstance->inline_strengthen_slot_value($instance_variable, $slot_name) >>
413 These methods all expect two arguments. The first is the name of a
414 variable, than when inlined, will represent the object
415 instance. Typically this will be a literal string like C<'$_[0]'>.
417 The second argument is a slot name.
419 The method returns a snippet of code that, when inlined, performs some
420 operation on the instance.
422 =item B<< $metainstance->inline_rebless_instance_structure($instance_variable, $class_variable) >>
424 This takes the name of a variable that will, when inlined, represent the object
425 instance, and the name of a variable that will represent the class to rebless
426 into, and returns code to rebless an instance into a class.
434 =item B<< Class::MOP::Instance->meta >>
436 This will return a L<Class::MOP::Class> instance for this class.
438 It should also be noted that L<Class::MOP> will actually bootstrap
439 this module by installing a number of attribute meta-objects into its