in reply to Re^2: RFC: Object::Proxy (or somesuch)
in thread RFC: Object::Proxy (or somesuch)
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^4: RFC: Object::Proxy (or somesuch)
by dragonchild (Archbishop) on Nov 19, 2004 at 21:02 UTC | |
Now, the average user of this screen will look at 2-3 invoices. Why should I pre-load 25-35 invoices, with some 50-70 DB queries, when I can defer loading until the user actually tells me which one they care about? Now, so far, you say "Just use another screen." But, I didn't write the Invoice object code. I am told I have to reuse code because my PHB needs to look good, but I am not allowed to modify it because my PHB has no clout. Enter Class::LazyLoad. The Invoice object doesn't even know it's being deferred, nor does it care. The Customer screen now loads really fast and all the information that used to be there still is. Being right, does not endow the right to be rude; politeness costs nothing. | [reply] |
by perrin (Chancellor) on Nov 19, 2004 at 23:02 UTC | |
| [reply] |
by stvn (Monsignor) on Nov 20, 2004 at 01:40 UTC | |
Trust me perrin, I have looked at all these modules, and at times even read the underlying source code, and decide against all of them. And in case you are interested, I will tell you why. After taking a brief glance at Class::LazyObject though, I think that it would do what you want without additional effort. This is from the docs of Class::LazyObject: Class::LazyObject automates creating a class for deflated objects that inflate to a particular other class. This is not what we are looking for. We want to proxy the actual class, then when needed inflate it to be the real class, but never have to deal with making a lazy class. Another point from Class::LazyObject's docs I found to go against our needs was this, in the docs for the inherit method (which is an important method since it seems to bind the lazy and non-lazy classes together): Class::LazyObject->inherit should only be called by any class that inherits from Class::LazyObject.From this I can decude that I will surely need to create a Lazy class in addition to my normal one. I just don't like that, it's extra work that doesn't need to be done even if it is "automated". The author of Class::LazyObject actually gives an excellent comparison of Class::LazyObject with Object::Realize::Later in the docs (you can find it here. In there the author points out an important difference between the visibility of Class::LazyObject and Object::Realize::Later While I had already decided Class::LazyObject was not what I needed, this description made me think that Object::Realize::Later was not what I wanted either. Transparency was an important component for my needs and I despise namespace pollution, especially in objects. As for Class::Proxy and Class::Proxy::Lite they are not doing the same thing as our module. Despite the Object::Proxy name, we realized very early on that this module was not really a proxy. So suffice to say, a proxy module would not fit the bill. However I have looked over these module as well when I was writing IOC::Proxy. Class::Proxy uses some odd Class::Listener object at it's base, and to be honest, I got tired of trying to trace what was happening. This opacity was not what I was looking for. As for Class::Proxy::Lite, this is what turned me off for that module: Apparently, it's not possible to catch calls to the can() and isa() methods on instances of Class::Proxy::Lite. This makes it impossible to implement a true proxy without defining UNIVERSAL::isa and UNIVERSAL::can, which I'm reluctant to do.It seemed to me that the author just didn't implement a can or isa function in Class::Proxy::Lite to catch it, since AUTOLOAD will not trap them. Although I there is a possibility that some of the details of how he chose to implement Class::Proxy::Lite got in the way of that happening. I didn't delve too much further in to see. There is also Class::Wrap by Simon Cozens. This module basically proxies the entire class by re-writing it's symbol table and moving the original methods into a ::hidden:: namespace. As with most of Simon's modules, it is an interesting bit of code which he threw out onto the CPAN and then never touched again. I see one major flaw in it being that he fails to account for inheritance (he only proxies the immediate class, and so all inherited methods will then not be proxied,... bug or feature,... you decide). I ultimately wrote IOC::Proxy to fit my needs, which were; to be able to proxy instances and not classes, to be able to proxy the full inheritance tree of methods, and to be virtually indistinguishable from the real thing. IOC::Proxy accomplishes all those goals, in a somewhat paranoid and slightly insane way. There is some details about how it does this in the docs if you care to read. In the end, I hear your point about not re-inventing the wheel. And CPAN is a wonderful resource, but by no means a complete resource. Before I code anything which I think I might be able to find on CPAN, I make an exhasutive search to see what is out there. Sometimes I use what I find, and other times I end up writing my own module, but never without thoroughly reading and digesting as much as I can about what is already there. After all, if I cannot reuse the actual code, I can at least reuse the experience and knowledge I find in that code.
-stvn
| [reply] |
by jplindstrom (Monsignor) on Nov 19, 2004 at 21:25 UTC | |
kewl! /J | [reply] |
|
Re^4: RFC: Object::Proxy (or somesuch)
by stvn (Monsignor) on Nov 19, 2004 at 21:19 UTC | |
The point of being able to lazyload just a single instance is basically to be as unintrusive as possible, while still allowing this to be possible. Let me explain in more detail. Say you want to lazy load ever instance of the class. Every single instance of My::Class is now lazily loaded. This is obvious, and how most of the class proxy/lazy loading module out there work. Now take this particular example (based on the IOC issues mentioned above in response to dio). My A constructor requires an instance of B, and my B constructor requires an instance of A. The best solution is to give A a real B instance, and give B a lazy-loaded A instance. Now say my C constructor requires an instance of A. I previously gave B a lazy-loaded A, however, there is no need to give C a lazy-loaded A, that is an unessecary level of indirection. But if lazy-loading was on a class level only, I would not be able to make this choice. With lazy-loading being available on a per-instance basis I can give C a real A instance. Of course the need (or desire) to fiddle at this low a level is a rare instance and one not likely to be an issue for anyone but me. However, this is exactly the issue that caused dragonchild and I to start talking about and building this module.
-stvn
| [reply] [d/l] |