views:

137

answers:

4

I have a variable that I need to pass to a subroutine. It is very possible that the subroutine will not need this variable, and providing the value for the variable is expensive. Is it possible to create a "lazy-loading" object that will only be evaluated if it is actually being used? I cannot change the subroutine itself, so it must still look like a normal Perl scalar to the caller.

+2  A: 

You might look into tying.

Chas. Owens
`tie` will not work the way the OP is looking for. The value of the tied variable will be evaluated when @_ is unpacked. The workarounds are to pass a reference to the tied variable, or to not unpack @_ until you can know if the value is needed.
Ven'Tatsu
+6  A: 

You'll want to look at Data::Lazy and Scalar::Defer. Update: There's also Data::Thunk and Scalar::Lazy.

I haven't tried any of these myself, but I'm not sure they work properly for an object. For that, you might try a Moose class that keeps the real object in a lazy attribute which handles all the methods that object provides. (This wouldn't work if the subroutine does an isa check, though, unless it calls isa as a method, in which case you can override it in your class.)

cjm
Scalar:Defer looks like it fits the bill. Fortunately, I will not be needing to use this on objects, just a plain-old (but long) string.
Thilo
+5  A: 

Data::Thunk is the most transparent and robust way of doing this that i'm aware of.

However, I'm not a big fan of it, or any other similar modules or techniques that try to hide themself from the user. I prefer something more explicit, like having the code using the value that's hard to compute simply call a function to retrieve it. That way you don't need to precompute your value, your intent is more clearly visible, and you can also have various options to avoid re-computing the value, like lexical closures, perl's state variables, or modules like Memoize.

rafl
+1  A: 

I would suggest stepping back and rethinking how you are structuring your program. Instead of passing a variable to a method that it might not need, make that value available in some other way, such as another method call, that can be called as needed (and not when it isn't).

In Moose, data like this is ideally stored in attributes. You can make attributes lazily built, so they are not calculated until they are first needed, but after that the value is saved so it does not need to be calculated a second time.

Ether
The problem is that it is not my program. It is a shell that runs Perl snippets provided by the end-user. I need to provide $_ for it (which it may or may not really need).
Thilo