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;
| [reply] [d/l] [select] |
|
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.
| [reply] [d/l] [select] |
|
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.
| [reply] [d/l] [select] |
|
$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;
# ...
} );
| [reply] [d/l] [select] |
|
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?
| [reply] [d/l] [select] |
|
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.)
| [reply] [d/l] [select] |
|
|
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.
| [reply] [d/l] [select] |
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.
| [reply] [d/l] |
Re: [Perl 6] Any provision for a "dereferencing object"?
by ambrus (Abbot) on May 29, 2007 at 16:38 UTC
|
| [reply] [d/l] |
|
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?
| [reply] |
|
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.
| [reply] [d/l] |
|
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.
| [reply] [d/l] [select] |
|
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...
| [reply] [d/l] |
|
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.
| [reply] |