|Do you know where your variables are?|
Tie Me Up, Tie Me Downby Zaxo (Archbishop)
|on Jan 14, 2005 at 04:43 UTC||Need Help??|
Concerning code factorization, efficiency and tied variables:
In the wake of Are lvalue methods (as properties) a good idea?, I've revisited an old node of mine, To Validate Data In Lvalue Subs. One thing that I realize now is that I didn't make clear how independent the Constrained class is from the notions of closures and lvalue subs. Constrained can be applied to any scalar variable, including references to anything.
What good is that? A tied interface is slower than simple assignment for a reason; it's doing something. The 40% (or whatever) extra overhead for assigning or fetching through the tied interface is trivial if you have work to do inside it. What work? Whatever is ubiquitous enough to factor this way! I think that that is more than "syntactic sugar", and it's sweeter, too.
For reference, here is a slightly updated and renamed version of Constrained,
That's much like the older code, but I've removed the stringency from FETCH() and added a dummy default validator. Those changes were to make subclassing easier. A subclass would typically override invalid() to get different error handling or validate() to have a common class-wide default test.
Data validation is the job the Tie::Constrained class does. That's an example of something you may want to do many times, the same way each time, every time a mutator is applied to your variable.
Off the top of my head, I can think of three basic ways to code those tests.
The first and most obvious one is dismal in practice. The mutation is done to your variable before you get to validate. You can't apply it to third-party code. Paste errors may gum you up. Maintainance is a nightmare. The limited checking of 1b) does nothing to inform you where the bad data crept in. The code has flashing neon signs saying "Factor me!"
The second is better, but it has problems of its own. The proliferation of classes confuses development. Overriding core functions and overloading core operators confuses everybody. The class packages represent a lot of perhaps tricky code to write. Factorization is pretty good, but nothing like . . .
Three. Once a variable is tied to its very own automatic validity check, every mutator will be checked before the variable is modified. That is true of old code and new, third-party code, perl modules, all without the code needing to know anything about it. No infrastructure at all. No special coding beyond the tie call.
That is code factoring with a vengence. I also consider it a particularly sparse and clean kind of OO code, where the object is the aggregate of variable, test and exception.
I'm considering doing a little more tuning and much pod writing to prepare a distribution for CPAN. I'll welcome your comments.