So I thought of a serious problem with part of this RFC. The bit
about using indirect object syntax...
> Instead, this RFC proposes that C<tie>'s operation become much more
> fundamental, simply translating functions via the existing indirect
> object syntax:
>
> tie Transaction %trans; # indirect object constructor
> $trans{$var} = $value ; # $obj->STORE($var, $value);
> lock $trans{$var}; # $obj->lock($var);
There's a nasty inconsistency there. Consider the following.
package Foo;
sub lock {
flock $_[0], LOCK_EX;
}
lock $trans{$var};
Normally, the Foo::lock() subroutine in the current package will be
called. However, if %trans is a tied hash to a class which defines a
lock() method (let's call it Lock::Ness) the meaning of the program
radically and unexpectedly changes. Instead of
C<Foo::lock($trans{$var})>, we now have C<$obj->lock($var)> and the
two routines can do something *completely* different.
This might have been your intention, to override the lock(0 function,
but it becomes extremely dangerous when you consider the effect of a
tied variable on interal code. You pass in a tied hash to a module
and somewhere deep in its guts it calls the function foo() on it, but
you have foo() defined as a method and your foo() has absolutly
nothing to do with their foo() causing havoc. Action at a distance.
The only possible recovery I can see is for the function currently in
scope to have a higher "precedence" than the tied method. So in our
example, the call to lock() remains a call to Foo::lock() and not to
the tied method.
The reverse situation, that of a tied method being accidentally turned
into a function call, shouldn't happen in normal circumstances. Only
problem is, reversing the precedence makes it near worthless. Read
on.
I just thought of a more fundemental problem. Looking at the
rationale for this...
Plus, if you want to support extra methods of your own, you must mix
object and tied calls:
$obj = tie %trans, 'Transaction';
$trans{$var} = $value;
$obj->lock($var);
Unfortunately, this defeats one of the key purposes of tie, which is OO
transparency. And, creating a class that supports both OO and tied
interfaces is difficult, requiring typeglobs or duplicate handler
functions.
Instead, this RFC proposes that C<tie>'s operation become much more
fundamental, simply translating functions via the existing indirect
object syntax:
tie Transaction %trans; # indirect object constructor
$trans{$var} = $value ; # $obj->STORE($var, $value);
lock $trans{$var}; # $obj->lock($var);
delete $trans{$var}; # $obj->delete($stuff);
foo %trans; # $obj->foo;
The idea is that by using the indirect object syntax, the tied
variable can call methods on itself beyond those which are built in.
But this doesn't really win you much besides some syntactic sugar.
Consider this code:
lock $trans{$var};
What if %trans is not tied? Then a lock() subroutine would have to be
in scope, which presumably you've exported as part of your tied
module. But that means you have to write function wrappers around
your methods, which is even more work than the simple method aliasing
for the OO/tie hybrid. And in the case of locking a key in a hash,
you can't do it because lock() will receive the value.
If the code is intended to be run *only* on tied variables, then you
could have just used a plain object and dropped the sugar.
--
Michael G Schwern http://www.pobox.com/~schwern/ [EMAIL PROTECTED]
Just Another Stupid Consultant Perl6 Kwalitee Ashuranse
Plus I remember being impressed with Ada because you could write an
infinite loop without a faked up condition. The idea being that in Ada
the typical infinite loop would be normally be terminated by detonation.
-- Larry Wall in <[EMAIL PROTECTED]>