http://qs321.pair.com?node_id=617875

This meditation was inspired by reading storing and using LoL path: indeed most of us could hardly make sense of the question being asked. After some thought AIUI it boils down to the OP's wanting to store a dereferencing chain (of a complex data structure) as a single "entity" somewhere. Now this is strictly impossible in Perl 5, although there are modules that can provide functionality that will come close to that. OTOH I wonder whether in Perl 6 there is or there could be any provision for such a thing, that is, for a $dereferencer object to "hold", say

<foo>[1]<bar><baz>[3]

in such a way that

$datastructure.$dereferencer

would DWIM.

I know I'd better ask this in p6l, but I've not been there for a long time and I prefer to discuss this topic here. Hopefully someone will report it there if judging it worth to end up in that place.

Update: I changed curlies to angular parens above, thanks to the observation by gaal. I knew, but constantly keep thinking in Perl 5...

Replies are listed 'Best First'.
Re: [Perl 6] Any provision for a "dereferencing object"?
by gaal (Parson) on May 28, 2007 at 20:52 UTC
    If you reverse their order, it's simply a closure:

    $dereferencer = { $^moose.<foo>[1]<bar><baz>[3] }; $dereferencer($datastructure);

    Otherwise, you're looking for something like adding $datastructure to a prototype class with $dereferencer as a method, kinda quirky.

    Update: two syntactical clarifications. {foo} is wrong because Perl 6 has no barewords; use either {'foo'} or the shorthand above that exploits the list quote operator. $^moose is just a placeholder variable, a scalable extension of the hardcoded $a and $b of sort comparators. There are other ways to express this idea.

    Update II (more to the point): I said quirky, but of course I didn't mean impossible. If you're dead set on .<foo>[1]<bar><baz>[3] as a method you can sure compose $datastructure to a role that implements it. Unless I'm messing up the syntax (in which case I hope to be corrected):

    role Profound { method dereferencer ($x) { $x.<foo>[1]<bar><baz>[3] } +} ($datastructure but Profound).dereferencer;
      In perl5, what about something like...
      my $a = []; $a->[1]{bar}{baz}[3] = 7; bless $a, "hrmph"; *hrmph::deref = sub { $_[0]->[1]{bar}{baz}[3] }; print "yeah: ", $a->deref, "\n";

      It's maybe not the clearest or most maintainable thing in the whole wide world, but it's not "impossible." You could even build on it to make it more readable, reliable, and more flexible in various ways.

      (UPDATE: I clicked the wrong reply button, so if there's a kind editor that could move me up a level?)

      UPDATE: Oh, I see what you're up to I think. Some function you build once and applicate anwhere. I am also a little surprised your $x->$deref.

      -Paul

        In perl5, what about something like...

        my $a = []; $a->[1]{bar}{baz}[3] = 7; bless $a, "hrmph"; *hrmph::deref = sub { $_[0]->[1]{bar}{baz}[3] }; print "yeah: ", $a->deref, "\n";

        Well, that's not quite the same thing, because you create a method for each "dereferencing chain". I was talking about putting it e.g. in some scalar or in an aggregate. But now that you got me thinking, this is certainly possible and even easier than what you wrote:

        my $x = []; $x->[1]{bar}{baz}[3] = 7; bless $x, "whatever"; my $deref = sub { $_[0]->[1]{bar}{baz}[3] }; print "yeah: ", $x->$deref, "\n";

        What's even more interesting is that the variable appearently doesn't need to be blessed at all, which I wouldn't have known nor suspected without trying. In fact the following works just the same too:

        my $x = []; $x->[1]{bar}{baz}[3] = 7; # bless $x, "whatever"; my $deref = sub { $_[0]->[1]{bar}{baz}[3] }; print "yeah: ", $x->$deref, "\n";
        It's maybe not the clearest or most maintainable thing in the whole wide world, but it's not "impossible."

        Well, what I wrote -literally- is still impossible: that is precisely to have a "dereferencing chain" as a self sustained "single entity", existing in and of itself without a reference to be applied to. In fact here we have a cheap workaround that is perfectly equivalent. Yet it's not, from the "philosophical" POV, exactly the same thing.

        UPDATE: Oh, I see what you're up to I think. Some function you build once and applicate anwhere. I am also a little surprised your $x->$deref.

        Well, that's a bit of common OO syntactical sugar: if $code contains a subref, then in

        $object->$code(@args);

        the corresponding sub is called as a method on $object. This is often used to implement callbacks in a way that personally I like:

        $object->record( name => 'doit', callback => sub { my $caller=shift; # ... } );

      If you reverse their order, it's simply a closure:

      $dereferencer = { $^moose.<foo>[1]<bar><baz>[3] }; $dereferencer($datastructure);

      Yep this is very akin to what Joost suggested for Perl 5 (and was also mentioned in the original thread), except that it's more 6ish. I was thinking... is in general the semantics of $datastructure.$dereferencer definite? Is it valid syntax anyway? If not, could a C<.> infix multi, or even a macro, be specified to "amount to" the function call specified above?

        multi sub infix:<at> ($dsc, Code $deref) { $deref($dsc); } my %data = ( foo => [ { quux => 3 }, { bar => { baz => [ 1, 2, 3, 4 ] +}, }, ], ); my $dereferencer = { .<foo>[1]<bar><baz>[3] }; say %data at $dereferencer;

        Works in Pugs. Since there doesn't seem to be any good documentation about macros yet, I don't know how to beautify the dereferencer construction syntax, but it ought to be trivial to make a macro that translates deref <foo><bar><baz>[1] to { .<foo><bar><baz>[1] }.

        UPDATE: Fixed some blaring typos in the code. Thanks for noting it, blazar. (For some reason, you can't define a Hash in Pugs with

        my Hash %foo = ( # something );
        At least I get a syntax error with Pugs 6.2.13.)

        --
        print "Just Another Perl Adept\n";

        Well, like I said in the update: for $datastructure to respond to the $dereferencer method, you need it to do a certain Role. This can be achieved on the fly.
Re: [Perl 6] Any provision for a "dereferencing object"?
by Joost (Canon) on May 28, 2007 at 20:50 UTC
    Interesting question. I don't know if there's any special construct in perl 6 to do this, but it's not THAT difficult to do something similar in perl 5:
    #!/usr/bin/perl -w use strict; my %a; $a{foo}[1]{bar}{baz}[3] = "bla"; my $path = sub :lvalue { $_[0]->{foo}[1]{bar}{baz}[3] }; print $path->(\%a),"\n"; $path->(\%a) = "bar"; print $path->(\%a),"\n";
    And you could extend this technique using closures to make the path dynamic.

Re: [Perl 6] Any provision for a "dereferencing object"?
by ambrus (Abbot) on May 29, 2007 at 16:38 UTC

      Thank you for the additional reference. Actually I'm not much concerned here with pragmatism, i.e. with how "to do it" coming close to the real thing (because discussion both here and in the linked thread show that this is possible in reasonably simple ways both under 5 and 6) as much as with "philosophy", i.e. the real thing itself, specifically the "tail without the animal": can it be a beast in and of itself in Perl 6?

        We made it really easy to write closures and deref them in Perl 6 so that people would not feel the need to invent special syntax for deferred evaluation. So basically, you use curlies to delimit any kind of "tail without the animal", and calling a closure is how you add the animal back in. And closures have the advantage of taking additional arguments if you want multiple degrees of "animal" freedom in your locator. S12 is now clarified to indicate that $object.$methodname() is able to call into a closure as well as into a named method. Thanks.
Re: [Perl 6] Any provision for a "dereferencing object"?
by rootcho (Pilgrim) on Jun 01, 2007 at 04:54 UTC
    hmm..
    In perl6 could we have something like this then :)
    my %hash = ( foo => { foo1 => {foo2 => 5 } }, bar => { baz => [ 1,2,3 ], foo2 => 33 }, ... )
    and then access this like :
    $hash<*><foo2> $hash<//><foo2>
    In this case '*' and '//' mean the same thing (just for illustration. regex-like and xpath-like syntax).
    This should return all 'foo2' element no matter how deep. Or :
    $hash<bar><//><foo2>
    Return only the second 'foo2'..and so on.. you get the idea.
    Or this better be done with external module ?
    This will make very easy implementing XPath and similar tools.
      Well, it would be wicked to use <*> to hold magic cookies, since that construct is supposed to only contain literal strings. However, Perl 6 already specs a multidimensional syntax in Synopsis 9 to do what you want:
      $hash{ **; 'foo2'} $hash{ 'bar'; **; 'foo2' }
      Whether this is actually implementable is another question...

        I don't see why it wouldn't be. At worst, you would need to do a breadth-first search through the whole datastructure (which, in the general case, is likely to be a graph rather than a tree). Of course, this may be terribly slow, but surely it's implementable.

        --
        print "Just Another Perl Adept\n";