Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Logical/defined or as lvalue

by jo37 (Deacon)
on Sep 03, 2024 at 17:01 UTC ( [id://11161546]=perlquestion: print w/replies, xml ) Need Help??

jo37 has asked for the wisdom of the Perl Monks concerning the following question:

Recently I played with the logical/defined or in a scenario where the result should be an lvalue. For the defined or (//) the documentation clearly states that the result is not an lvalue. While this is not mentioned for the logical or (||), it holds there too.

I don't know the reason for this behaviour, but it prevents the usage of these operators as a substitute for the non-existing (binary) "Elvis operator" (?:), where X ?: Z would act like X ? X : Z, without evaluating X twice.

To my surprise I realized that dereferencing a reference to the result of an or operator provides an lvalue, given the operands are lvalues. That is, the following expression does compile and works: ${\(X // Y)}++.
I could not find anything in the documentation that would forbid such a usage.

So my questions are:

  • What is the reason for the logical/defined or operators not to provide an lvalue as result?
  • Would changing this behaviour break any existing code?
  • Is the usage of ${\(X // Y)} as an lvalue well-defined behaviour?

Here is a complete example:

#!/usr/bin/perl use v5.24; use warnings; use experimental 'signatures'; say "This is perl $]"; sub f :lvalue ($k) { state $href = {a => 10}; $href->{$k}; } sub g :lvalue ($k) { state $href = {b => 20}; $href->{$k}; } eval q{ (f($_) || g($_))++ for qw(a b); 1; } or warn $@; ${\(f($_) // g($_))}++ for qw(a b); say "f(a) = ", f('a'); say "g(b) = ", g('b'); __DATA__ Can't modify logical or (||) in postincrement (++) at (eval 5) line 2, + near ")++" This is perl 5.032001 f(a) = 11 g(b) = 21

Greetings,
🐻

$gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$

Replies are listed 'Best First'.
Re: Logical/defined or as lvalue
by hv (Prior) on Sep 03, 2024 at 21:54 UTC

    What is the reason for the logical/defined or operators not to provide an lvalue as result?

    I don't know. It may have been oversight, or there may have been an explicit or implicit rationale that has most likely been lost in the mists of time.

    Would changing this behaviour break any existing code?

    My first guess would be autovivification: $h{$_} behaves differently in lvalue and rvalue contexts, which is already enough to cause regular confusion. Also any classes that provide overloading of these operators is likely to have been designed to the current behaviour.

    Is the usage of ${\(X // Y)} as an lvalue well-defined behaviour?

    I think it probably depends on X and Y, but in the cases where it is legal to take the reference, I think I'd expect the dereference to be well-behaved. In other words: where it works, I wouldn't expect it to suddenly stop working.

      I almost hazarded a similar guess with similar rationale (having to account for an undef result being the destination target for autovivification). My gut reaction to concept is that it's something that I'd likely at least "ding" were I to see it in a code review (conceivably it's similar but shorter for doing an assignment to different places in different legs of an if/else maybe but feels like tending towards obfuscation . . . meh).

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

      Hi hv's ghost writer, :)

      > My first guess would be autovivification: $h{$_} behaves differently in lvalue and rvalue contexts, which is already enough to cause regular confusion.

      Do you have an example?

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

      My first guess would be autovivification: $h{$_} behaves differently in lvalue and rvalue contexts,...

      True, but currently the usage of X // Y as an lvalue results in a compile error. I'm not sure if this is any different in overloading.

      Update:
      One overlooked detail:

      Also any classes that provide overloading of these operators...

      Logical operators cannot be overloaded.

      Greetings,
      🐻

      $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$

      That's strange, I was definitely logged in when I wrote that, and I'm still logged in (as hv).

        For future reference, you can just send a /msg to gods and they can change the ownership of the node to yourself.

Re: Logical/defined or as lvalue
by LanX (Saint) on Sep 03, 2024 at 19:57 UTC
    I wasted too much time on this ;)

    Anyway, my best suggestion, please don't use this deref-ref syntax for the sake of readability

    Try something like the following ors or defs and you are free to chain even more than two operators and assign too.

    sub ors :lvalue { $_ && return $_ for @_ ; return $_[-1]; } # define analogous &defs ors($x,$y,$z) = 42;

    This could also be included in a module like List::Util (if really missing, compare any and all

    Regarding documentation: the perlop Doc for // also covers || and &&.

    They talk at length about returning the scalar value of the first operand because of the Boolean test, this might be related.

    FWIW, I was also experimenting with

    sub lv(&) :lvalue { ${ \( $_[0]->() ) } } lv{ $a // $b } = 666;

    But this doesn't work because I can't specify that the prototype & code-block is an lvalue too. ( Probably a posteriori???)

    Finally I discovered what looks like a bug at least in 5.36 inside the debugger.

    feature 'signatures' seems to be enabled by default when testing sub declarations inside a prompt of perl -de0

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

    ¹) I'm having a deja-vu right now, did we discuss this before?

      It wasn't Perl if there were no other way to do it.

      Maybe my questions were misleading: I'm not searching for a solution to a specific problem. I'm asking if a feature was desirable and feasible.

      Greetings,
      🐻

      $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$
Re: Logical/defined or as lvalue
by ikegami (Patriarch) on Sep 03, 2024 at 19:43 UTC

    Is ( X || Y ) = Z; really something we want to see in our code? When would it be useful?

      We have ($w? $x : $y)= $z so why not?
        Well yes, according to Wikipedia is PHP implementing the "Elvis operator"
        • $x ?: $y
        as
        • $x ? $x : $y

        But I think Perl has bigger fish to frie.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery

        Many reasons why not. I already gave the two primary ones: lack of readability (due to its rare and unexpected use) and lack of usefulness.

        If anything, I read your post as an argument against ( W ? X : Y ) = Z. But that has at least some modicum of usefulness.

      When would it be useful?

      Consider items from @list to be counted, with one "given" set and a "rest". A pre-initialized hash %h1 holds the "given" set and an empty hash %h2 counts the rest. Then we could:

      ${\($h1{$_} // ($h2{$_} //= 0))}++ for @list;

      Greetings,
      🐻

      $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$

        If you're going to count them all, I don't see the point of having the counts split across two hashes. If there's an important distinction between the two sets of strings, you would need those lists, and you could access the counts of either lists.

        If I wanted to do this, I'd count only in one hash and use a hash-slice to extract the "given" ones.

        Less code and more flexible.

        Update

        Alternatively a HoH where the first key decides what is given or rest.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11161546]
Approved by marto
Front-paged by LanX
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (8)
As of 2024-09-09 12:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.