in reply to RFC: The lightning-rod operator

I have several problems with the "The Need" paragraph already ...

1) you are proposing two "safe" operators in one, the first to avoid magic (autovivification at hash access) the second to introduce magic (ignore error of missing method).

I don't find this consistent.

2) The number of edge cases for the large amount of operators makes Perl hard to memorize, we are not only running out of keyboard characters, but learning Perl becomes increasingly complicated.

3) DWIM shouldn't violate orthogonality, i.e. the ability to understand the syntax logically by composing smaller concepts to a consistent whole.

If P5P wants to extent syntax, than a better support for autoboxing would be the way I'd favour for efficiency and flexibility!

use strict; use warnings; use Data::Dump qw/dd/; my $get = sub { my ($ref ,@path)=@_; for my $member (@path){ return undef unless exists $ref->{$member}; $ref = $ref->{$member}; } return $ref; }; my %hash = ( a=> {b=> {c=> 666} }); dd \%hash; dd $hash{a}->$get(qw/b c/); dd $hash{a}->$get(qw/x x x/); # no autovivification #dd $hash{a}{x}{x}{x}; # autovivification dd \%hash;
->
{ a => { b => { c => 666 } } } 666 undef { a => { b => { c => 666 } } }

Please note that:

a) the name of the method is (or can be) self explanatory ( get is just a guess)

b) this approach is backward compatible, the Perl implementation might be slow but will always work as a fall back

c) performance could be easily improved by XS code in an intermediate step

d) the solution is generic, i.e. any other "missing" operator could be implemented/experimented with and hence orthogonal

e) any new syntax like ~> or whatever could be additionally implemented with a clearly named twin autobox method

Sorry if I didn't read your hole post and didn't supply an example implementation for $call but a flue with fever limits my attention span ATM ;-)

Cheers Rolf
(addicted to the Perl Programming Language and ☆☆☆☆ :)
Je suis Charlie!

PS: As a side note, I was first thinking of realizing something like a $safe-method to handle both cases

$name = $user[$idx] -> {'name'}; # may create a hash $name = $user[$idx] -> $safe -> {'name'}; # leaves @user alone $name = $person -> name; # chokes on undef $name = $person -> $safe -> name; # passes undef on

But this would not only imply too much slow magic like a proxy class but also mangle two different concepts in one operator (see point 1)

Replies are listed 'Best First'.
Re^2: RFC: The lightning-rod operator
by martin (Friar) on Jan 23, 2016 at 23:54 UTC

    Thank you for your comments so far, and thank you for pointing out another technique to avoid autovivification (other than the autovivification pragma on CPAN).

    I suppose some of your points will get less of an issue if you do get around to read the rest of the article. In particular, you may rest assured that I don't want to suggest new dereferencing operators.

    To the contrary, the lightning-rod or fuse operator I was talking about would make such operators unnecessary.

      Sorry but your ideas are not trivial or easy to grasp, so I have to go little by little. =)

      I find the desired short cut behaviour to catch undef even more problematic than the rest.

      I'd rather prefer a catch_undef { BLOCK } command, because the block would be explicit about what is caught without much explanation.

      This can be emulated (at least) with

      my $h_b = {}; my $x = eval { use warnings FATAL => 'uninitialized' ; $h_b->{velocity}." mph"; } // 'unknown'; print $x;

      I tried to construct some syntactic sugar

      sub catch_undef (&) { my $code_ref = shift; eval { use warnings FATAL => 'uninitialized' ; $code_ref->() }; }

      but I'm running into two problems:

      1) Obviously pragmas are lexically scoped, I seem to remember there are some obscure tricks to manipulate the warning flags of a coderef (something with $^H ?) but I'm too lazy at the moment.

      2) seems to be a bug in the parser, because I get a weird syntax error for

       catch_undef { $ref->{velocity} .'mph' }  //  "unknown";

      Too many arguments for main::catch_undef at /tmp/tst.pl line 29, near "//  "unknown""

      using || instead solves the parsing problem (but not the task)

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

        I'd rather prefer a catch_undef { BLOCK } command, because the block would be explicit about what is caught without much explanation.

        While throwing exceptions or returning early from subroutines are indeed ways of taking short-cuts, it is tricky to get the amount of control I am looking for with existing language constructs.

        Keep in mind that the suggested operator does not need something that would trigger a warning or error to work, nor would it change the behaviour of similar warnings in the same block.

        The method calling chain $a->foo->bar^^->baz->qux, say, would give us a short-cut after bar() but nowhere else. Likewise, the dereferencing chain $a->[1]->[2]^^->[3] would autovivify $a->[1] but not $a->[1]->[2].