Hello,
Please forgive my ignorance of perl6 and of proper procedures for this
kind of thing. Below I describe an operator (or syntax really) I've been
pining for under perl5. I already know the syntax proposal is obsolete in
the context of perl6 syntax, but perhaps somebody with more understanding
could adapt the concept to fit the current state-of-the-art.
Cheers,
Lyren Brown
=head1 TITLE
Conditional, Short-Circuiting Dereference Operator C<&&-E<gt>>.
=head1 VERSION
Maintainer: Lyren Brown <[EMAIL PROTECTED]>
Date: 1 Mar 2002
Version: 1
Mailing List: perl6-language
Number: 1
=head1 ABSTRACT
An operator for conditionally dereferencing a scalar based on whether
it is a valid reference. The operator is short-circuiting to avoid
unwanted or unnecessary auto-vivification or symbolic dereferencing.
It returns the scalar if the scalar is not a reference.
=head1 DESCRIPTION
The C<&&-E<gt>> dereferencing syntax can be used instead of C<-E<gt>>
for any type of dereferencing.
=head2 Examples
my $ref = [];
my $foo = $ref->[0]{bar}{baz}; # $foo is undef.
Because of auto-vivification, the array that C<$ref> references now
has an element 0 which is a one-element anonymous hash which has a key
"bar" whose value is a zero-element anonymous hash.
my $ref = [];
my $foo = $ref&&->[0]&&->{bar}&&->{baz}; # $foo is undef.
Because if its short-circuiting nature, the C<&&-E<gt>> operator
prevents auto-vivification. So the array that C<$ref> references
continues to have zero elements.
$ref->[0] = 3;
$foo = $ref&&->[0]&&->{bar}&&->{baz}; # $foo is 3.
Unlike C<-E<gt>>, C<&&-E<gt>> never attempts to symbolically
dereference, so the setting of strict refs is irrelevant.
$ref->[0]{bar} = 'hello';
$foo = $ref&&->[0]&&->{bar}&&->{baz}; # $foo is "hello".
$ref->[0]{bar}[0] = 'test';
$foo = $ref&&->[0]&&->{bar}&&->{baz}; # Error: Not a HASH reference.
The C<&&-E<gt>> operator also works for closure references and method
calls.
my $ref = sub { shift };
my $foo = $ref&&->('info')&&->('msg'); # $foo is "info".
$ref = sub { my $type = shift; sub { "$type: @_" } };
$foo = $ref&&->('info')&&->('msg'); # $foo is "info: msg".
$ref = undef;
$foo = $ref&&->get('blah'); # $foo is undef;
$ref = new Foo;
$foo = $ref&&->get('blah'); # $foo is result of get() method.
=head2 Short-Hand
Braces without an arrow use either C<-E<gt>> or C<&&-E<gt>> semantics
depending on which was used latest in the dereferencing expression.
my $foo = $ref&&->[0]&&->{bar}&&->{baz};
my $foo = $ref&&->[0]{bar}{baz}; # Equivalent to previous line.
my $foo = $ref->[0]&&->{bar}->{baz}; # Use &&-> just for 'bar' lookup.
=head2 Perl5 Alternatives
There are many ways to get around the absence of an operator like
C<&&-E<gt>> in Perl5, but none are as clear, concise and potentially
efficient as C<&&-E<gt>>. Take the following example:
my $foo = $r&&->('bar')&&->[0]{baz};
If we maintain as an invariant that intermediate nodes either evaluate
to false (e.g. C<undef>) or are a reference of the right type, then
the following Perl5 idiom can be used:
my $foo =
$r && $r->('bar') && $r->('bar')->[0] && $r->('bar')->[0]{baz};
Or using temporary variables:
my $foo = do { my ($r1, $r2);
$r && ($r1 = $r->('bar')) && ($r2 = $r1->[0]) && $r2->{baz} };
We can add the is-a-reference check that C<&&-E<gt>> provides as
follows:
my $foo = do { my ($r1, $r2);
ref $r ? ref ($r1 = $r->('bar')) ? ref ($r2 = $r1->[0]) ?
$r2->{baz} : $r2 : $r1 : $r };
We can use closures to abstract some of the code and avoid temporary
variables while retaining the short-circuiting semantics.
sub da (&$$) { ref $_[1] ? $_[0]->($_[1]->[$_[2]]) : $_[1] }
sub dh (&$$) { ref $_[1] ? $_[0]->($_[1]->{$_[2]}) : $_[1] }
sub dc (&$@) { ref $_[1] ? $_[0]->($_[1]->(@_[2..$#_])) : $_[1] }
sub dm (&$$@) {
ref $_[1] ? $_[0]->($_[1]->${\$_[2]}(@_[3..$#_])) : $_[1] }
my $foo =
dc { da { dh { shift } shift, 'baz' } shift, 0 } $r, 'bar';
=head1 IMPLEMENTATION
Unknown.
=head1 REFERENCES
RFC 177: A Natural Syntax Extension For Chained References (aka
Multidimensional Arrays/Hashes)
L<Hash::NoVivify>
http:[EMAIL PROTECTED]/msg47001.html
http://www.perl.com/pub/a/2001/07/25/onion.html
"What is now $foo->[$a] will be reduced to $foo[$a] in Perl 6."
=cut