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