How do I... tie hashes/arrays?

8 views
Skip to first unread message

Ingo Blechschmidt

unread,
Apr 19, 2005, 10:02:41 AM4/19/05
to perl6-l...@perl.org
Hi,

quoting an old post from Luke (http://xrl.us/ftet):
> C<tie>ing is going to work quite differently, from what I hear.
> So it might be possible to overload any function to call a
> special version when your type of array is used. You just have
> to write all the special versions.

So is the following valid?
class TiedArray is Array {
method push(*@things) {
...;
}
}

my TiedArray @array;
push @array: ...; # calls our push
unshift @array: ...; # calls Array::unshift
# Will push @array, ... DWIM?

How do I define the method/sub responsible for @array.[index]/
%hash.{key}?
class TiedArray is Array {
# Possibility #1
method *postcircumfix:<'[', ']'>(TiedArray $self, $index) {
return new Proxy:
FETCH => {...},
STORE => {...};
}

# Possibility #2
multi sub *postcircumfix:<'[', ']'>(TiedArray $self, $index) {
# Body as above
}

# Possibility #3
method FETCH($index) {...}
method STORE($index, $val) {...}

# Possibility #4
method GET($index) is rw {
# Body as in possibility #1
}
}

FWIW, I like possibility #4 best.


--Ingo

--
Linux, the choice of a GNU | self-reference, n. - See self-reference
generation on a dual AMD |
Athlon! |

Larry Wall

unread,
Apr 19, 2005, 11:52:13 AM4/19/05
to perl6-l...@perl.org
On Tue, Apr 19, 2005 at 02:02:41PM +0000, Ingo Blechschmidt wrote:
: Hi,
:
: quoting an old post from Luke (http://xrl.us/ftet):
: > C<tie>ing is going to work quite differently, from what I hear.
: > So it might be possible to overload any function to call a
: > special version when your type of array is used. You just have
: > to write all the special versions.
:
: So is the following valid?
: class TiedArray is Array {
: method push(*@things) {
: ...;
: }
: }
:
: my TiedArray @array;
: push @array: ...; # calls our push
: unshift @array: ...; # calls Array::unshift
: # Will push @array, ... DWIM?

That doesn't quite work the way you have it. You've used the syntax
for declaring the types of the individual elements of your array,
equivalent to

my @array is Array of TiedArray;

Instead, you want:

my @array is TiedArray;

: How do I define the method/sub responsible for @array.[index]/

: %hash.{key}?
: class TiedArray is Array {
: # Possibility #1
: method *postcircumfix:<'[', ']'>(TiedArray $self, $index) {
: return new Proxy:
: FETCH => {...},
: STORE => {...};
: }
:
: # Possibility #2
: multi sub *postcircumfix:<'[', ']'>(TiedArray $self, $index) {
: # Body as above
: }
:
: # Possibility #3
: method FETCH($index) {...}
: method STORE($index, $val) {...}
:
: # Possibility #4
: method GET($index) is rw {
: # Body as in possibility #1
: }
: }
:
: FWIW, I like possibility #4 best.

None of those are quite right, because you have to be prepared to deal
not only with slices, but with multiple dimensions of slices.

But to answer your question, #1 is probably the closest to what is
actually going on under the covers, though it needs an "is rw" if you
want to be able to assign to your slice. However, I don't doubt that
someone will come up with various kinds of syntactic sugar to paper
over the lvalue/rvalue proxying system, which is designed to keep the
identification operations distinct from the getter/setter operations.
It's not designed to make people happy who want to confuse those
issues. We have macros for that.

That's the philosophy, anyway. It may yet turn out that proxying
completely fouls up the optimizer in this case. Sometimes a
cut-and-paste has the benefit of being concrete enough for the
optimizer to understand, whereas the abstraction is too, er, abstract.
If the rw method can just pass the raw slice information off to its
FETCH and STORE, it's probably a wash. If it has to generate a new
data structure to pass, that gets more expensive, and is likely to
be slower than merely duplicating the code that defines the identity
operationally rather than in a data structure. However, that being
said, there's enough flexibility in the FETCH/STORE proxy that you
could "defactor" the identification code out to the various handlers
and get the same benefit. A syntactic sugar solution like #4 might
do just that.

If the proxy generating method does nothing but pass its input off
to the handlers, then we have the case that the object can serve as
its own proxy, in which case you could probably define the FETCH and
STORE directly in the class, much like your #3. However, we'd have
to deal with the fact that the proxy's FETCH and STORE are relying
on lexical scoping to get the slicing info into their closures,
while #3's FETCH and STORE are getting that info via direct parameters.
So we can't just freely interconvert those.

Is that enough muddy thinking for one morning?

Larry

Thomas Sandlaß

unread,
Apr 25, 2005, 12:38:09 PM4/25/05
to perl6-l...@perl.org
Larry Wall wrote:
> Depends on whether the user is actually expecting equal MMD there,
> or tie-breaking between multi methods within the particular class.
> My gut-level feeling is that they expect the latter.

With combined .method and method: syntax we also could have a nice
top priority or innermost single invocant that possibly redispatches
outwards. With sufficient type information the selection might already
happen at compile time.


> : > ... However, that being


> : > said, there's enough flexibility in the FETCH/STORE proxy that you
> : > could "defactor" the identification code out to the various handlers
> : > and get the same benefit.

> :
> : Well, isn't the "defactorized" code just a bunch of multi subs?
>
> I don't think of it that way. Considering the code is bound to a
> particular proxy object before it is ever called, it seems to fall
> even more into the category of multi method rather than multi sub.
>
> This is one of the big flying leaps that Perl 6 is trying to take.
> We've had lots of MMD implementations in the world, but Perl 6 is
> attempting to make that orthogonal to all the other scoping mechanisms,

I agree. We have:
1) backwards/forward along the call chain
2) outwards/inwards for lexical scopes
3) specificity on the (ordered) set of invocant arguments


> including lexical scopes and class scopes. If there's prior art,
> I'm not aware of it.

The Cecil people have done some research under which pre-conditions
a global MMD can be broken up into modularized MMD without loosing
type safety. This limits Perl6's innovation to providing a nice
syntax for it and making type safety optional---or better two ends
of a spectrum. Actually I hope type safety is not really optional but
deferred to runtime exceptions or undefined values that eventually
result in an exception.


> I suppose the non-brain-burning view of it is
> that any extra lexical or class scope dimension just turns into an
> extra absolute constraint on which subset of the global subs of that
> short name can be called.

Well, isn't MMD just another non-local control flow exception?
At the first level the object's vtable is some kind of pre-calculated
dispatch. From there on it goes outwards through lexical dispatchers.
--
TSa (Thomas Sandlaß)

Reply all
Reply to author
Forward
0 new messages