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


Reply via email to