http://www.perlmonks.org?node_id=409099

stvn and I have been coding up an extremely lightweight & very simple deferred-loading proxy object. The goal was to be as unobstrusive as possible, while still allowing for useful lazyloading.

There are several usage forms:

package My::Class use Object::Proxy; ....
Now, all My::Class objects will defer loading until they're used.

Let's say you are the user of a class and you want it to be lazy-loaded.

use Object::Proxy 'Proxy::This'; my $obj = Proxy::This->new( @args );
$obj is now a deferred load.

Or, you can import a proxy() method that will allow you to turn on lazy-loading for a class (or even just an instance) at runtime. There is also an unproxy() method, to turn it off.

Proxied objects will respect isa(), can(), overloading, and (nearly) all forms of direct access.

We found several modules on CPAN that do similar things, but they all required a lot more work on the programmer's part. Our way, you don't even have to write your class with any lazyloading in mind. The caller can choose to lazyload your class and you don't even know the difference.

First, does anyone think they would like this?

Second, what should we call it? Object::Proxy is kind-of our development name, but we were hoping for something better. Object::LazyLoader is another thought, but it's ... well ... ugly.

Being right, does not endow the right to be rude; politeness costs nothing.
Being unknowing, is not the same as being stupid.
Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Replies are listed 'Best First'.
Re: RFC: Object::Proxy (or somesuch)
by diotalevi (Canon) on Nov 19, 2004 at 18:46 UTC

    What about Object::Realize::Later, Class::LazyObject, or Data::Lazy? How would your module differ?

    How is this laziness effected anyhow? Is it going to make map Foo::Bar->new( foo => $_ ), LIST slimmer where Foo::Bar::new is something simple like return bless { @_ }, $class?

    What is the case where you'd realize benefits from this and at what point are those benefits lost?

    If you name your module after a proxy then I'd expect it to be something SOAP-like - your object stays around to relay stuff to and from the actual object which exists somewhere else. So don't use the term 'proxy' if the idea is about having something be lazy.

      What about Object::Realize::Later, Class::LazyObject, or Data::Lazy? How would your module differ?

      Data::Lazy seems to be only for variables, this module would be for objects.

      With Class::LazyObject and Object::Realize::Later you seem to be required to create a ::Lazy package of some kind, which later on would turn into a non-lazy version of itself. For my needs at least, this was too much overhead.

      How is this laziness effected anyhow? Is it going to make map Foo::Bar->new( foo => $_ ), LIST slimmer where Foo::Bar::new is something simple like return bless { @_ }, $class?

      I doubt you will get much gains in efficiency from simple constructors, but then why would you want to lazy load it anyway? The real goal (at least for me, I cannot speak for dragonchild) is the ability to have an object, which looks like a Duck, and quacks like a Duck, but is only really a Duck at the very last possible second.

      If you name your module after a proxy then I'd expect it to be something SOAP-like - your object stays around to relay stuff to and from the actual object which exists somewhere else. So don't use the term 'proxy' if the idea is about having something be lazy.

      I disagree that proxy == SOAP-esque. The Proxy pattern is from the GoF Design Patterns book, and is just simply what you describe without the distributed part. I agree that proxy is not a good name, hence the reason for this meditation, we can't figure out a better one :)

      -stvn

        Could you make this more general so you could make lazy expressions? So instead of getting a number back from 0 + $foo->bar you get back a value which will defer running ->bar until it is actually needed? Sort of like promises from E.

        Maybe you could just name your module Object::Realize::Later::Lighter if the improvement is that you avoid having a ::Lazy package. Are you really proposing having so many lazy packages that avoiding adding a ::Lazy one is going to help? Partially I wonder because AFAICT, Object::Realize::Later is already sort of a standard when people solve this problem.

      Object::Realize::Later and Class::LazyObject require a lot of work on the part of the lazy object's author. Our module can be used with classes that don't even know they're being loaded lazily. For example, you could lazy-load DBI with this module.

      We differ from Data::Lazy because we're not tied and we're not specific to data structure. We're specific to classes and objects.

      The laziness is effected by substituting a lazy constructor for the real constructor(s). Our constructor is sub new { bless @_ }. (No, we don't expect to be inherited from.) Then, when any method is called or any direct access is attempted or any overloaded operator is used, we build the object, then redispatch the requested access/method/overload.

      So, the benefits are that we defer all construction until such a time as you absolutely need the object. Potentially, if you don't use the object, it never gets constructed. There is a slight penalty for the first access to the object, but it's very slight (almost negligible).

      I think the word Proxy goes away in favor of LazyLoad. Better?

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: RFC: Object::Proxy (or somesuch)
by jmcnamara (Monsignor) on Nov 19, 2004 at 19:39 UTC

    This seems a little like Class::Autouse:

    Class::Autouse allows you to specify a class the will only load when a method of that class is called. For large classes that might not be used during the running of a program, such as Date::Manip, this can save you large amounts of memory, and decrease the script load time.

    Although, that is not to say that there shouldn't be another approach.

    --
    John.

      Also, with this module you can lazy load something on an instance basis as well, most all the other options only allow class level deferment. You load instances like this:

      my $instance = Class::Plugin::LazyLoad->proxy_instance('My::Class', @c +onstructor_args);
      The $instance variable is now a lazy-loader object which will only inflate when you touch it. One of my big goals for this was to be as non-invasive as possible.

      -stvn
        Do you have a real-world example of when this would be useful? I understand that it's not exactly like these other modules, but it's close enough that it's hard for me to see the point.
      Class::Plugin::LazyLoad is different because it works at the constructor level vs. Class::Autouse which works at the compilation level. Does that help?

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: RFC: Object::Proxy (or somesuch)
by Mutant (Priest) on Nov 19, 2004 at 19:12 UTC
    As far as a name, how about simply 'Object:Lazy'?