1Object::Realize::Later(U3s)er Contributed Perl DocumentatOibojnect::Realize::Later(3)
2
3
4
6 Object::Realize::Later - Delayed creation of objects
7
9 package MyLazyObject;
10
11 use Object::Realize::Later
12 becomes => 'MyRealObject',
13 realize => 'load';
14
16 The "Object::Realize::Later" class helps with implementing transparent
17 on demand realization of object data. This is related to the tricks on
18 autoloading of data, the lesser known cousin of autoloading of func‐
19 tionality.
20
21 On demand realization is all about performance gain. Why should you
22 spent costly time on realizing an object, when the data on the object
23 is never (or not yet) used? In interactive programs, postponed real‐
24 ization may boost start-up: the realization of objects is triggered by
25 the use, so spread over time.
26
28 Construction
29
30 use(Object::Realize::Later OPTIONS)
31
32 When you invoke ("use") the "Object::Realize::Later" package, it
33 will add a set of methods to your package (see section "Added to
34 YOUR class").
35
36 Option --Default
37 becomes <required>
38 believe_caller <false>
39 realize <required>
40 source_module <becomes>
41 warn_realization <false>
42 warn_realize_again <false>
43
44 . becomes CLASS
45
46 Which type will this object become after realization.
47
48 . believe_caller BOOLEAN
49
50 When a method is called on the un-realized object, the AUTOLOAD
51 checks whether this resolves the need. If not, the realization
52 is not done. However, when realization may result in an object
53 that extends the functionality of the class specified with
54 "becomes", this check must be disabled. In that case, specify
55 true for this option.
56
57 . realize METHOD⎪CODE
58
59 How will transform. If you specify a CODE reference, then this
60 will be called with the lazy-object as first argument, and the
61 requested method as second.
62
63 After realization, you may still have your hands on the lazy
64 object on various places. Be sure that your realization method
65 is coping with that, for instance by using Memoize. See exam‐
66 ples below.
67
68 . source_module CLASS
69
70 if the class (a package) is included in a file (module) with a
71 different name, then use this argument to specify the file
72 name. The name is expected to be the same as in the "require"
73 call which would load it.
74
75 . warn_realization BOOLEAN
76
77 Print a warning message when the realization starts. This is
78 for debugging purposes.
79
80 . warn_realize_again BOOLEAN
81
82 When an object is realized, the original object -which func‐
83 tioned as a stub- is reconstructed to work as proxy to the
84 realized object. This option will issue a warning when that
85 proxy is used, which means that somewhere in your program there
86 is a variable still holding a reference to the stub. This lat‐
87 ter is not problematic at all, although it slows-down each
88 method call.
89
90 Added to YOUR class
91
92 $obj->AUTOLOAD
93
94 When a method is called which is not available for the lazy object,
95 the AUTOLOAD is called.
96
97 $obj->can(METHOD)
98
99 Object::Realize::Later->can(METHOD)
100
101 Is the specified METHOD available for the lazy or the realized ver‐
102 sion of this object? It will return the reference to the code.
103
104 Example:
105
106 MyLazyObject->can('lazyWork') # true
107 MyLazyObject->can('realWork') # true
108
109 my $lazy = MyLazyObject->new;
110 $lazy->can('lazyWork'); # true
111 $lazy->can('realWork'); # true
112
113 $obj->forceRealize
114
115 You can force the load by calling this method on your object. It
116 returns the realized object.
117
118 Object::Realize::Later->isa(CLASS)
119
120 Is this object a (sub-)class of the specified CLASS or can it
121 become a (sub-)class of CLASS.
122
123 Example:
124
125 MyLazyObject->isa('MyRealObject') # true
126 MyLazyObject->isa('SuperClassOfLazy'); # true
127 MyLazyObject->isa('SuperClassOfReal'); # true
128
129 my $lazy = MyLazyObject->new;
130 $lazy->isa('MyRealObject'); # true
131 $lazy->isa('SuperClassOfLazy'); # true
132 $lazy->isa('SuperClassOfReal'); # true
133
134 $obj->willRealize
135
136 Returns which class will be the realized to follow-up this class.
137
138 Object::Realize::Later internals
139
140 The next methods are not exported to the class where the `use' took
141 place. These methods implement the actual realization.
142
143 Object::Realize::Later->import(OPTIONS)
144
145 The OPTIONS used for "import" are the values after the class name
146 with "use". So this routine implements the actual option parsing.
147 It generates code dynamically, which is then evaluated in the call‐
148 ers name-space.
149
150 Object::Realize::Later->realizationOf(OBJECT [,REALIZED])
151
152 Returns the REALIZED version of OBJECT, optionally after setting it
153 first. When the method returns "undef", the realization has not
154 yet taken place or the realized object has already been removed
155 again.
156
157 Object::Realize::Later->realize(OPTIONS)
158
159 This method is called when a "$object-"forceRealize()> takes place.
160 It checks whether the realization has been done already (is which
161 case the realized object is returned)
162
164 About lazy loading
165
166 There are two ways to implement lazy behaviour: you may choose to check
167 whether you have realized the data in each method which accesses the
168 data, or use the autoloading of data trick.
169
170 An implementation of the first solution is:
171
172 sub realize {
173 my $self = shift;
174 return $self unless $self->{_is_realized};
175
176 # read the data from file, or whatever
177 $self->{data} = ....;
178
179 $self->{_is_realized} = 1;
180 $self;
181 }
182
183 sub getData() {
184 my $self = shift;
185 return $self->realize->{data};
186 }
187
188 The above implementation is error-prone, where you can easily forget to
189 call realize(). The tests cannot cover all ordenings of method-calls
190 to detect the mistakes.
191
192 The second approach uses autoloading, and is supported by this package.
193 First we create a stub-object, which will be transformable into a real‐
194 ized object later. This transformation is triggered by AUTOLOAD.
195
196 This stub-object may contain some methods from the realized object, to
197 reduce the need for realization. The stub will also contain some
198 information which is required for the creation of the real object.
199
200 "Object::Realize::Later" solves the inheritance problems (especially
201 the isa() and can() methods) and supplies the AUTOLOAD method. Class
202 methods which are not defined in the stub object are forwarded as class
203 methods without realization.
204
205 Traps
206
207 Be aware of dangerous traps in the current implementation. These prob‐
208 lems appear by having multiple references to the same delayed object.
209 Depending on how the realization is implemented, terrible things can
210 happen.
211
212 The two versions of realization:
213
214 * by reblessing
215 This is the safe version. The realized object is the same object
216 as the delayed one, but reblessed in a different package. When
217 multiple references to the delayed object exists, they will all be
218 updated at the same, because the bless information is stored within
219 the refered variable.
220
221 * by new instance
222 This is the nicest way of realization, but also quite more danger‐
223 ous. Consider this:
224
225 package Delayed;
226 use Object::Realize::Later
227 becomes => 'Realized',
228 realize => 'load';
229
230 sub new($) {my($class,$v)=@_; bless {label=>$v}, $class}
231 sub setLabel($) {my $self = shift; $self->{label} = shift}
232 sub load() {$_[0] = Realized->new($_[0]->{label}) }
233
234 package Realized; # file Realized.pm or use use(source_module)
235 sub new($) {my($class,$v)=@_; bless {label=>$v}, $class}
236 sub setLabel($) {my $self = shift; $self->{label} = shift}
237 sub getLabel() {my $self = shift; $self->{label}}
238
239 package main;
240 my $original = Delayed->new('original');
241 my $copy = $original;
242 print $original->getLabel; # prints 'original'
243 print ref $original; # prints 'Realized'
244 print ref $copy; # prints 'Delayed'
245 $original->setLabel('changed');
246 print $original->getLabel; # prints 'changed'
247 print $copy->getLabel; # prints 'original'
248
249 Examples
250
251 Example 1
252
253 In the first example, we delay-load a message. On the moment the mes‐
254 sage is defined, we only take the location. When the data of the mes‐
255 sage is taken (header or body), the data is autoloaded.
256
257 package Mail::Message::Delayed;
258
259 use Object::Realize::Later
260 ( becomes => 'Mail::Message::Real'
261 , realize => 'loadMessage'
262 );
263
264 sub new($) {
265 my ($class, $file) = @_;
266 bless { filename => $file }, $class;
267 }
268
269 sub loadMessage() {
270 my $self = shift;
271 Mail::Message::Real->new($self->{filename});
272 }
273
274 In the main program:
275
276 package main;
277 use Mail::Message::Delayed;
278
279 my $msg = Mail::Message::Delayed->new('/home/user/mh/1');
280 $msg->body->print; # this will trigger autoload.
281
282 Example 2
283
284 Your realization may also be done by reblessing. In that case to
285 change the type of your object into a different type which stores the
286 same information. Is that right? Are you sure? For simple cases,
287 this may be possible:
288
289 package Alive;
290 use Object::Realize::Later
291 becomes => 'Dead',
292 realize => 'kill';
293
294 sub new() {my $class = shift; bless {@_}, $class}
295 sub jump() {print "Jump!\n"}
296 sub showAntlers() {print "Fight!\n"}
297 sub kill() {bless(shift, 'Dead')}
298
299 package Dead;
300 sub takeAntlers() {...}
301
302 In the main program:
303
304 my $deer = Alive->new(Animal => 'deer');
305 my $trophy = $deer->takeAntlers();
306
307 In this situation, the object (reference) is not changed but is reb‐
308 lessed. There is no danger that the un-realized version of the object
309 is kept somewhere: all variable which know about this partical deer see
310 the change.
311
312 Example 3
313
314 This module is especially usefull for larger projects, which there is a
315 need for speed or memory reduction. In this case, you may have an extra
316 overview on which objects have been realized (transformed), and which
317 not. This example is taken from the MailBox modules:
318
319 The Mail::Box module tries to boost the access-time to a folder. If
320 you only need the messages of the last day, why shall all be read? So,
321 MailBox only creates an invertory of messages at first. It takes the
322 headers of all messages, but leaves the body (content) of the message
323 in the file.
324
325 In MailBox' case, the Mail::Message-object has the choice between a
326 number of Mail::Message::Body's, one of which has only be prepared to
327 read the body when needed. A code snippet:
328
329 package Mail::Message;
330 sub new($$)
331 { my ($class, $head, $body) = @_;
332 my $self = bless {head => $head, body => $body}, $class;
333 $body->message($self); # tell body about the message
334 }
335 sub head() { shift->{head} }
336 sub body() { shift->{body} }
337
338 sub loadBody()
339 { my $self = shift;
340 my $body = $self->body;
341
342 # Catch re-invocations of the loading. If anywhere was still
343 # a reference to the old (unrealized) body of this message, we
344 # return the new-one directly.
345 return $body unless $body->can('forceRealize');
346
347 # Load the body (change it to anything which really is of
348 # the promised type, or a sub-class of it.
349 my ($lines, $size) = .......; # get the data
350 $self->{body} = Mail::Message::Body::Lines
351 ->new($lines, $size, $self);
352
353 # Return the realized object.
354 return $self->{body};
355 }
356
357 package Mail::Message::Body::Lines;
358 use base 'Mail::Message::Body';
359
360 sub new($$$)
361 { my ($class, $lines, $size, $message) = @_;
362 bless { lines => $lines, size => $size
363 , message => $message }, $class;
364 }
365 sub size() { shift->{size} }
366 sub lines() { shift->{lines} }
367 sub message() { shift->{message);
368
369 package Mail::Message::Body::Delayed;
370 use Object::Realize::Later
371 becomes => 'Mail::Message::Body',
372 realize => sub {shift->message->loadBody};
373
374 sub new($)
375 { my ($class, $size) = @_;
376 bless {size => $size}, $class;
377 }
378 sub size() { shift->{size} }
379 sub message(;$)
380 { my $self = shift;
381 @_ ? ($self->{message} = shift) : $self->{messages};
382 }
383
384 package main;
385 use Mail::Message;
386 use Mail::Message::Body::Delayed;
387
388 my $body = Mail::Message::Body::Delayed->new(42);
389 my $message = Mail::Message->new($head, $body);
390
391 print $message->size; # will not trigger realization!
392 print $message->can('lines'); # true, but no realization yet.
393 print $message->lines; # realizes automatically.
394
396 This module is part of Object-Realize-Later distribution version 0.16,
397 built on March 25, 2007. Website: http://perl.overmeer.net/orl/
398
400 Copyrights 2001-2004-2007 by Mark Overmeer <perl@overmeer.net>.For
401 other contributors see Changes.
402
403 This program is free software; you can redistribute it and/or modify it
404 under the same terms as Perl itself. See
405 http://www.perl.com/perl/misc/Artistic.html
406
407
408
409perl v5.8.8 2007-03-25 Object::Realize::Later(3)