Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

RFC: "assignary" operator ?= :

by richard.sharpe (Sexton)
on Dec 07, 2019 at 16:01 UTC ( #11109808=perlmeditation: print w/replies, xml ) Need Help??

Hello guys,

I would like having new type of assignment operator in perl, the combination of assignment and ternary operator (therefore calling it "assignary"):

?= :

Not in context of regular expressions, not related with (?=) in any way, but in regular assignment. I haven't found something like that in perlop.

Suggested meaning:

$var ?= "something" : "something else";

would be equivalent to:

$var = $var ? "something" : "something else";

Advantage of the first: more compact, as not writing $var two times.

What do you think about possible existence of such hybrid of ternary and assignment operators?

Replies are listed 'Best First'.
Re: RFC: "assignary" operator ?= :
by LanX (Cardinal) on Dec 07, 2019 at 16:13 UTC
    Are you sure you need this?

    Looks like an exotic edge case for me ...

    $var ||= "something else" is far more common.

    ... and Perl has already too many operators and changing the parser should be to complicated.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      I wouldn't call it a need, just preference. I would like "exploiting" such feature this way:

      $var1 ?= die "ERROR: \$var1 already set." : $var2;

      Maybe you'll see more elegant way how to do such thing.

      Your suggestion with ||= is not ternary, just "binary", if I understand that correctly.

        > not ternary, just "binary",

        yes it's binary.

        > $var1 ?= die "ERROR: \$var1 already set." : $var2;

        Thanks for demonstrating your use case, it's even stranger than I expected! ;-)

        die will not return a value - actually it won't return at all.

        > Maybe you'll see more elegant way how to do such thing.

        Yes with a properly named custom-function operating on an alias.

        something like

        sub init { die "ERROR: \$var already set." if defined $_[0]; $_[0] = $_[1]; } init $var1 => 'value1'; # pretty elegant, right? init $var2 => 'value2'; init $var3 => 'value3';

        Please note the defined° , cause else wise you'd miss false values like 0 or "". (which renders your requirement for a new operator a bit useless)

        UPDATE:
        • if you need the proper $var name use PadWalker
        • use Carp to report from the perspective of the caller

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        °) a shorter way would have been $_[0] // die 'ERROR: ...';

        Off by one, it's the inverted case :)

        $var1 ?= die "ERROR: \$var1 already set." : $var2;

        would be far clearer as

        die "ERROR: \$var1 already set." if $var1; $var1 = $var2;

        This is a pretty cute alternative:

        sub empty ($) :lvalue { if ($_[0]) { require Carp; if (eval { require PadWalker }) { my $varname = PadWalker::var_name(1, \$_[0]); Carp::croak("$varname is not empty, stopped"); } Carp::croak("Variable is not empty, stopped"); } $_[0]; } # Asserts that $var1 is "empty" (i.e. the empty string, 0, or undef) a +nd assigns $var2 as the new value. empty $var1 = $var2; # Can also be used like this to assert $var1 is empty without assignin +g a new value. empty $var1;
Re: RFC: "assignary" operator ?= :
by shmem (Chancellor) on Dec 07, 2019 at 22:25 UTC

    I like it. Very much. Looks to me like a very concise and logical addition to operators modifying the LHS, like *= /= ||= and such. And it is readable, fluently!

    $var ?= "something" : "something else";

    "If $var is set, assign to it 'something', else 'something else'"

    "Elegant as f*ck", as a cow-orker coined a python expression.

    I'd really like to have that operator added. If I find the time (and brainz) to whip up a proposal with patches, I'll do. Hopefully.

    Thanks!

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      What's the use case which justifies extending Perl's codebase for such an exotic feature?

      I can hardly imagine a reason to map non-Boolean values to a previously Boolean $var without confusing any maintainer.

      Using a new variable is always better then.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        What's the use case which justifies extending Perl's codebase for such an exotic feature?

        Concise expressiveness. The ternary ? : is a shortcut for a more convoluted simple if/else

        my $var; if($cond) { $var = 'this'; } else { $var = 'that'; }

        to be written as

        my $var = $cond ? 'this' : 'that';

        which is one line compared to 5, 6 or 7, depending on indentation style.

        We have more of such subtle operators, eg. ||= vs. //=, where the first checks the LHS truthiness, and the second checks the LHS definedness.

        Writing

        $var = $var ? 'this' : 'that';

        just looks and feels as silly as

        $value = $value * 5; $next = $next + 1;

        instead of

        $value *= 5; $next++;

        For the same reasons, I like the compound operator x!! so much, because it lets me set up a parameter list based on truthiness of variables:

        $result = build_shed( logs => 24, (screws => 120) x!! @screwdrivers, (nails => 360) x!! @hammers, );

        Otherwise, I'd had to say:

        my %materials = (logs => 24); $materials{screws} = 120 if @screwdrivers; $materiasl{nails} = 360 if @hammers; $result = build_shed(%materials);

        While the second variant is one line less, I regard the first variant as much more readable, and I don't have to introduce a temporary hash just for the sake of building function arguments. Note that in the second variant, the hash name is misspelt as materiasl at the 'nails' case, small bug caught by strict, but annoying. So, instead of

        $var = $var ? 'this' : 'that';

        I'd rather like to see

        $var ?= 'this' : 'that';

        because it binds the condition to the LHS in the same way as ||= and //= do.

        I can hardly imagine a reason to map non-Boolean values to a previously Boolean $var without confusing any maintainer.

        Who said that $var was boolean? It could hold any value, and this value is checked for truthiness.

        Anyways - de gustibus non est disputandem.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: RFC: "assignary" operator ?= :
by tobyink (Canon) on Dec 08, 2019 at 21:47 UTC

    You can think of it as an "upgrading" operation for a boolean variable.

    Like if a variable contains a Perl boolean, you can upgrade it to a JSON boolean:

    $var ?= JSON::PP::true : JSON::PP::false;

    Or you can upgrade a Perl boolean to some HTML:

    my $is_ready = 1; $is_ready = 0 if $service->not_configured(); $is_ready = 0 if $service->payment->status() ne 'paid'; $is_ready ?= '<span class="green">yes</span>' : '<span class="red">no< +/span>'; print "<p>Service ready? $is_ready</p>";

      convoluted? contrived? dilluted? word? ... unconvincing example

      my $is_ready = 1; $is_ready = 0 if $service->not_configured(); $is_ready = 0 if $service->payment->status() ne 'paid'; $is_ready or print "<p>Service ready? <span class="red">no</span></p>"; $is_ready and print gettext('yes ready');
Re: RFC: "assignary" operator ?= :
by kcott (Bishop) on Dec 09, 2019 at 05:53 UTC

    G'day richard.sharpe,

    $var ?= "something" : "something else";

    I suspect something along these lines would do what you want using existing syntax:

    $var = ("something else", "something")[!!$var];

    Some examples:

    $ perl -E 'my $x; $x = (0,1)[!!$x]; say $x' 0 $ perl -E 'my $x = ""; $x = (0,1)[!!$x]; say $x' 0 $ perl -E 'my $x = "X"; $x = (0,1)[!!$x]; say $x' 1

    From "Re^2: RFC: "assignary" operator ?= :":

    $var1 ?= die "ERROR: \$var1 already set." : $var2;

    You could do something rather exotic like:

    $ perl -E 'my $x = ""; $x = (42, $x && die "Set: $x")[!!$x]; say $x' 42 $ perl -E 'my $x = "X"; $x = (42, $x && die "Set: $x")[!!$x]; say $x' Set: X at -e line 1.

    But ask yourself:

    • Do you fully understand what's happening with that code?
    • Will the next maintainer fully understand what's happening with that code?
    • Wouldn't a simple if/else block be easier to write, read, understand and maintain?

    — Ken

      $var is repeated thus missing the point
Re: RFC: "assignary" operator ?= : ( conditional assignment , golf, death by diabetes )
by Anonymous Monk on Dec 09, 2019 at 02:13 UTC

    New operators jerk my knee jerk

    But they come and they go

    but it they come they must come correct in perlop, no half assing like Postfix Dereference

    assignary ? No

    Its conditional assignment

    Also not ter-signment , tri-sign, con-sign

    $var = $var ? JSON::PP::true : JSON::PP::false; $var ?= JSON::PP::true : JSON::PP::false; $var = $var ? JSON::PP::true : JSON::PP::false; $var ?= JSON::PP::true : JSON::PP::false; ($coo ?= $fudge : $brownie ) ?= $blondie : $oatmeal; ($coo ?= $fudge : $brownie ) ?= $blondie : $oatmeal; ($coo ?= $fudge : $brownie ) ?= $blondie : $oatmeal; ($coo ?= $fudge : $brownie ) ?= $blondie : $oatmeal; $coo = $coo ? $fudge : $brownie; $coo = $coo ? $blondie : $oatmeal;

    diabetes, a pleasant way to die?

      thanks :)

      you forgot mention "assholy trinity" as possible name for such operator, it would be very on-topic in this community :)

        > "assholy trinity" ... it would be very on-topic in this community :)

        You start a "request for comments" and then you call us assholes?

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: RFC: "assignary" operator ?= : ( source Filter::PPI::Transform )
by Anonymous Monk on Dec 11, 2019 at 06:29 UTC

    Source filter?

    Should be easy with PPI something...

    PPI::Document PPI::Statement PPI::Token::Symbol '$foo' PPI::Token::Whitespace ' ' PPI::Token::Operator '?' ################## PPI::Token::Operator '=' ################## PPI::Token::Whitespace ' ' PPI::Token::Symbol '$bar' PPI::Token::Whitespace ' ' PPI::Token::Operator ':' ################## PPI::Token::Whitespace ' ' PPI::Token::Symbol '$baz' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Statement PPI::Token::Symbol '$foo' PPI::Token::Whitespace ' ' PPI::Token::Operator '?' ################## PPI::Token::Operator '=' ################## PPI::Token::Whitespace ' ' PPI::Structure::List ( ... ) PPI::Token::Whitespace ' ' PPI::Statement::Expression PPI::Token::Word 'rand' PPI::Structure::List ( ... ) PPI::Token::Whitespace ' ' PPI::Token::Whitespace ' ' PPI::Token::Operator ':' ################## PPI::Token::Whitespace ' ' PPI::Structure::List ( ... ) PPI::Token::Whitespace ' ' PPI::Statement::Expression PPI::Token::Symbol '$baz' PPI::Token::Whitespace ' ' PPI::Token::Structure ';' PPI::Token::Whitespace '\n'

    Filter::PPI::Transform - Tiny adapter module from PPI::Transform to source filter
    PPI::Transform
    PPI::Transform::UpdateCopyright - Demonstration PPI::Transform class
    PPI-Transform-Sequence-v0.0.3
    Tiny binder to combine multiple PPI::Transform objects 12 Nov 2012 13:43:39 GMT
    Perl-Squish-1.06
    Reduce Perl code to a few characters as possible 08 Apr 2009 11:07:41 GMT

      Proof of concept

      #!/usr/bin/perl -- BEGIN{ package PPI::Transform::ConditionalAssignment; use strict; use warnings; use Params::Util qw{_STRING _INSTANCE}; use PPI::Transform (); use parent 'PPI::Transform'; our $VERSION = '0.1'; # VERSION sub document { my $self = shift; my $document = _INSTANCE(shift, 'PPI::Document') or return undef; my $elements = $document->find( sub { $_[1]->isa('PPI::Token::Operator') or return ''; $_[1]->content eq '?' or return ''; $_[1]->snext_sibling->isa('PPI::Token::Operator') or return '' +; $_[1]->snext_sibling->content eq '=' or return ''; return 1; } ); return undef unless defined $elements; return 0 unless $elements; my $changes = 0; foreach my $question ( @$elements ) { my $symbol = $question->sprevious_sibling->clone; my $equals = $question->snext_sibling; $equals->insert_after( $symbol ); $symbol->insert_after( $question->remove ); $changes++; } return $changes; } 1; $INC{'PPI/Transform/ConditionalAssignment.pm'}=__FILE__; } # BEGIN package main; use Filter::PPI::Transform 'PPI::Transform::ConditionalAssignment'; for my $foo ( 0 .. 1 ) { my $bar = $foo; $foo ?= 'one' : 'zero'; print "$foo\n"; $bar ?= ('one '.rand): ('zero '.rand); print "$bar\n"; } print "let me know " ? "should I stay" : "or should I go"; __END__ $ perl ppi-transform-conditional-assignment.pl zero zero 0.563323974609375 one one 0.086761474609375 should I stay

        Good luck implementing an infix operator with that.

        (I've tried.)

Re: RFC: "assignary" operator ?= :
by Anonymous Monk on Dec 10, 2019 at 03:57 UTC
    Please. We no longer live in a world where we need to save bytes or keystrokes. Don't muddy the water just because you can.

      From my point of view, it's not just about bytes or keystrokes, but about command verbalization efficiency and (subjective, of course) elegance. When I command somebody, I don't want to say it twice :). Perl gives you a lot of freedom of choices, allows a lot of "artism", for example in comparison with Python, which is more rigid. And this suggestion is about further development of this Perl's unique nature. Tim Toady likes it.

      A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (4)
As of 2020-07-02 09:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?