1Object::Realize::Later(U3s)er Contributed Perl DocumentatOibojnect::Realize::Later(3)
2
3
4

NAME

6       Object::Realize::Later - Delayed creation of objects
7

SYNOPSIS

9        package MyLazyObject;
10
11        use Object::Realize::Later
12           becomes => 'MyRealObject',
13           realize => 'load';
14

DESCRIPTION

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

METHODS

28   Construction
29       use(Object::Realize::Later %options)
30           When you invoke ("use") the "Object::Realize::Later" package, it
31           will add a set of methods to your package (see section "Added to
32           YOUR class").
33
34            -Option            --Default
35             becomes             <required>
36             believe_caller      <false>
37             realize             <required>
38             source_module       <becomes>
39             warn_realization    <false>
40             warn_realize_again  <false>
41
42           becomes => CLASS
43             Which type will this object become after realization.
44
45           believe_caller => BOOLEAN
46             When a method is called on the un-realized object, the AUTOLOAD
47             checks whether this resolves the need.  If not, the realization
48             is not done.  However, when realization may result in an object
49             that extends the functionality of the class specified with
50             "becomes", this check must be disabled.  In that case, specify
51             true for this option.
52
53           realize => METHOD|CODE
54             How will transform.  If you specify a CODE reference, then this
55             will be called with the lazy-object as first argument, and the
56             requested method as second.
57
58             After realization, you may still have your hands on the lazy
59             object on various places.  Be sure that your realization method
60             is coping with that, for instance by using Memoize.  See examples
61             below.
62
63           source_module => CLASS
64             if the class (a package) is included in a file (module) with a
65             different name, then use this argument to specify the file name.
66             The name is expected to be the same as in the "require" call
67             which would load it.
68
69           warn_realization => BOOLEAN
70             Print a warning message when the realization starts.  This is for
71             debugging purposes.
72
73           warn_realize_again => BOOLEAN
74             When an object is realized, the original object -which functioned
75             as a stub- is reconstructed to work as proxy to the realized
76             object.  This option will issue a warning when that proxy is
77             used, which means that somewhere in your program there is a
78             variable still holding a reference to the stub.  This latter is
79             not problematic at all, although it slows-down each method call.
80
81   Added to YOUR class
82       $obj->AUTOLOAD()
83           When a method is called which is not available for the lazy object,
84           the AUTOLOAD is called.
85
86       $obj->can($method)
87       Object::Realize::Later->can($method)
88           Is the specified $method available for the lazy or the realized
89           version of this object?  It will return the reference to the code.
90
91           example:
92
93              MyLazyObject->can('lazyWork')      # true
94              MyLazyObject->can('realWork')      # true
95
96              my $lazy = MyLazyObject->new;
97              $lazy->can('lazyWork');            # true
98              $lazy->can('realWork');            # true
99
100       $obj->forceRealize()
101           You can force the load by calling this method on your object.  It
102           returns the realized object.
103
104       Object::Realize::Later->isa($class)
105           Is this object a (sub-)class of the specified $class or can it
106           become a (sub-)class of $class.
107
108           example:
109
110            MyLazyObject->isa('MyRealObject')      # true
111            MyLazyObject->isa('SuperClassOfLazy'); # true
112            MyLazyObject->isa('SuperClassOfReal'); # true
113
114            my $lazy = MyLazyObject->new;
115            $lazy->isa('MyRealObject');            # true
116            $lazy->isa('SuperClassOfLazy');        # true
117            $lazy->isa('SuperClassOfReal');        # true
118
119       $obj->willRealize()
120           Returns which class will be the realized to follow-up this class.
121
122   Object::Realize::Later internals
123       The next methods are not exported to the class where the `use' took
124       place.  These methods implement the actual realization.
125
126       Object::Realize::Later->import(%options)
127           The %options used for "import" are the values after the class name
128           with "use".  So this routine implements the actual option parsing.
129           It generates code dynamically, which is then evaluated in the
130           callers name-space.
131
132       Object::Realize::Later->realizationOf( $object, [$realized] )
133           Returns the $realized version of $object, optionally after setting
134           it first.  When the method returns "undef", the realization has not
135           yet taken place or the realized object has already been removed
136           again.
137
138       Object::Realize::Later->realize(%options)
139           This method is called when a "$object-"forceRealize()> takes place.
140           It checks whether the realization has been done already (is which
141           case the realized object is returned)
142

DETAILS

144   About lazy loading
145       There are two ways to implement lazy behaviour: you may choose to check
146       whether you have realized the data in each method which accesses the
147       data, or use the autoloading of data trick.
148
149       An implementation of the first solution is:
150
151        sub realize {
152            my $self = shift;
153            return $self unless $self->{_is_realized};
154
155            # read the data from file, or whatever
156            $self->{data} = ....;
157
158            $self->{_is_realized} = 1;
159            $self;
160        }
161
162        sub getData() {
163            my $self = shift;
164            return $self->realize->{data};
165        }
166
167       The above implementation is error-prone, where you can easily forget to
168       call realize().  The tests cannot cover all ordenings of method-calls
169       to detect the mistakes.
170
171       The second approach uses autoloading, and is supported by this package.
172       First we create a stub-object, which will be transformable into a
173       realized object later.  This transformation is triggered by AUTOLOAD.
174
175       This stub-object may contain some methods from the realized object, to
176       reduce the need for realization.  The stub will also contain some
177       information which is required for the creation of the real object.
178
179       "Object::Realize::Later" solves the inheritance problems (especially
180       the isa() and can() methods) and supplies the AUTOLOAD method.  Class
181       methods which are not defined in the stub object are forwarded as class
182       methods without realization.
183
184   Traps
185       Be aware of dangerous traps in the current implementation.  These
186       problems appear by having multiple references to the same delayed
187       object.  Depending on how the realization is implemented, terrible
188       things can happen.
189
190       The two versions of realization:
191
192       ·   by reblessing
193
194           This is the safe version.  The realized object is the same object
195           as the delayed one, but reblessed in a different package.  When
196           multiple references to the delayed object exists, they will all be
197           updated at the same, because the bless information is stored within
198           the refered variable.
199
200       ·   by new instance
201
202           This is the nicest way of realization, but also quite more
203           dangerous.  Consider this:
204
205            package Delayed;
206            use Object::Realize::Later
207                 becomes => 'Realized',
208                 realize => 'load';
209
210            sub new($)      {my($class,$v)=@_; bless {label=>$v}, $class}
211            sub setLabel($) {my $self = shift; $self->{label} = shift}
212            sub load()      {$_[0] = Realized->new($_[0]->{label}) }
213
214            package Realized;  # file Realized.pm or use use(source_module)
215            sub new($)      {my($class,$v)=@_; bless {label=>$v}, $class}
216            sub setLabel($) {my $self = shift; $self->{label} = shift}
217            sub getLabel()  {my $self = shift; $self->{label}}
218
219            package main;
220            my $original = Delayed->new('original');
221            my $copy     = $original;
222            print $original->getLabel;     # prints 'original'
223            print ref $original;           # prints 'Realized'
224            print ref $copy;               # prints 'Delayed'
225            $original->setLabel('changed');
226            print $original->getLabel;     # prints 'changed'
227            print $copy->getLabel;         # prints 'original'
228
229   Examples
230       Example 1
231
232       In the first example, we delay-load a message.  On the moment the
233       message is defined, we only take the location.  When the data of the
234       message is taken (header or body), the data is autoloaded.
235
236        package Mail::Message::Delayed;
237
238        use Object::Realize::Later
239          ( becomes => 'Mail::Message::Real'
240          , realize => 'loadMessage'
241          );
242
243        sub new($) {
244            my ($class, $file) = @_;
245            bless { filename => $file }, $class;
246        }
247
248        sub loadMessage() {
249            my $self = shift;
250            Mail::Message::Real->new($self->{filename});
251        }
252
253       In the main program:
254
255        package main;
256        use Mail::Message::Delayed;
257
258        my $msg    = Mail::Message::Delayed->new('/home/user/mh/1');
259        $msg->body->print;     # this will trigger autoload.
260
261       Example 2
262
263       Your realization may also be done by reblessing.  In that case to
264       change the type of your object into a different type which stores the
265       same information.  Is that right?  Are you sure?  For simple cases,
266       this may be possible:
267
268        package Alive;
269        use Object::Realize::Later
270             becomes => 'Dead',
271             realize => 'kill';
272
273        sub new()         {my $class = shift; bless {@_}, $class}
274        sub jump()        {print "Jump!\n"}
275        sub showAntlers() {print "Fight!\n"}
276        sub kill()        {bless(shift, 'Dead')}
277
278        package Dead;
279        sub takeAntlers() {...}
280
281       In the main program:
282
283        my $deer   = Alive->new(Animal => 'deer');
284        my $trophy = $deer->takeAntlers();
285
286       In this situation, the object (reference) is not changed but is
287       reblessed.  There is no danger that the un-realized version of the
288       object is kept somewhere: all variable which know about this partical
289       deer see the change.
290
291       Example 3
292
293       This module is especially useful for larger projects, which there is a
294       need for speed or memory reduction. In this case, you may have an extra
295       overview on which objects have been realized (transformed), and which
296       not.  This example is taken from the MailBox modules:
297
298       The Mail::Box module tries to boost the access-time to a folder.  If
299       you only need the messages of the last day, why shall all be read?  So,
300       MailBox only creates an invertory of messages at first.  It takes the
301       headers of all messages, but leaves the body (content) of the message
302       in the file.
303
304       In MailBox' case, the Mail::Message-object has the choice between a
305       number of Mail::Message::Body's, one of which has only be prepared to
306       read the body when needed.  A code snippet:
307
308        package Mail::Message;
309        sub new($$)
310        {   my ($class, $head, $body) = @_;
311            my $self = bless {head => $head, body => $body}, $class;
312            $body->message($self);          # tell body about the message
313        }
314        sub head()     { shift->{head} }
315        sub body()     { shift->{body} }
316
317        sub loadBody()
318        {   my $self = shift;
319            my $body = $self->body;
320
321            # Catch re-invocations of the loading.  If anywhere was still
322            # a reference to the old (unrealized) body of this message, we
323            # return the new-one directly.
324            return $body unless $body->can('forceRealize');
325
326            # Load the body (change it to anything which really is of
327            # the promised type, or a sub-class of it.
328            my ($lines, $size) = .......;    # get the data
329            $self->{body} = Mail::Message::Body::Lines
330                                 ->new($lines, $size, $self);
331
332            # Return the realized object.
333            return $self->{body};
334        }
335
336        package Mail::Message::Body::Lines;
337        use base 'Mail::Message::Body';
338
339        sub new($$$)
340        {   my ($class, $lines, $size, $message) = @_;
341            bless { lines => $lines, size => $size
342                  , message => $message }, $class;
343        }
344        sub size()    { shift->{size} }
345        sub lines()   { shift->{lines} }
346        sub message() { shift->{message);
347
348        package Mail::Message::Body::Delayed;
349        use Object::Realize::Later
350            becomes => 'Mail::Message::Body',
351            realize => sub {shift->message->loadBody};
352
353        sub new($)
354        {   my ($class, $size) = @_;
355            bless {size => $size}, $class;
356        }
357        sub size() { shift->{size} }
358        sub message(;$)
359        {   my $self = shift;
360            @_ ? ($self->{message} = shift) : $self->{messages};
361        }
362
363        package main;
364        use Mail::Message;
365        use Mail::Message::Body::Delayed;
366
367        my $body    = Mail::Message::Body::Delayed->new(42);
368        my $message = Mail::Message->new($head, $body);
369
370        print $message->size;         # will not trigger realization!
371        print $message->can('lines'); # true, but no realization yet.
372        print $message->lines;        # realizes automatically.
373

SEE ALSO

375       This module is part of Object-Realize-Later distribution version 0.21,
376       built on January 24, 2018. Website: http://perl.overmeer.net/CPAN/
377

LICENSE

379       Copyrights 2001-2018 by [Mark Overmeer]. For other contributors see
380       ChangeLog.
381
382       This program is free software; you can redistribute it and/or modify it
383       under the same terms as Perl itself.  See http://dev.perl.org/licenses/
384
385
386
387perl v5.30.0                      2019-07-26         Object::Realize::Later(3)
Impressum