Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Shortcut operator for $a->{'b'}=$b if $b;

by rokadave (Sexton)
on Sep 20, 2005 at 16:21 UTC ( #493501=perlquestion: print w/ replies, xml ) Need Help??
rokadave has asked for the wisdom of the Perl Monks concerning the following question:

I'm making a data structure and I don't want any empty keys. This code works: $a->{'b'}=$b if $b; The problem is that's way too verbose... and the real code is much uglier than that. I was wondering if there's some great shortcut operator. I got excited about ||=, but it's not really the samething. ? and : don't exactly work either. The point is to have no key 'b' exist if $b is false.

Comment on Shortcut operator for $a->{'b'}=$b if $b;
Re: Shortcut operator for $a->{'b'}=$b if $b;
by ikegami (Pope) on Sep 20, 2005 at 16:24 UTC

    I assume you mean $b is a long expression, so you'd rather avoid having it twice. If so, you could topicalize $b:

    { local $_ = $b; $a->{b} = $_ if defined $_; }

    or (update)

    $a->{b} = $_ foreach grep defined, $b;

    or you could add everything then remove undefined values:

    delete @$a{ grep { not defined $a->{$_} } keys %$a };
      Yes. If there's no shortcut operator, then your suggestion is the cleanest it'll get. I was hoping there existed an "assign-if-true" operator.

        You could write the operator yourself:

        sub assign_if_defined { $_[0] = $_[1] if defined $_[1]; } assign_if_defined($a->{'b'}, $b);

        By the way, I'm using defined since you said you didn't want empty keys. Checking for truthfullness (as you have been doing) removes both empty and false keys. Just remove the word defined for a truth test.

Re: Shortcut operator for $a->{'b'}=$b if $b;
by halley (Prior) on Sep 20, 2005 at 16:26 UTC
    No really swift code I can think of, which prevents the keys from being inserted. But if you can allow empty keys to exist briefly, you can audit them afterwards:
    $a = { d=>1, e=>2, f=>3, g=>undef, h=>0, i=>4 }; delete @$a{ grep { not $a->{$_} } keys %$a };
    Of course, that's just shifting the ugliness.

    --
    [ e d @ h a l l e y . c c ]

      A little less ugly audit:

      for (keys %$a) { delete $a->{$_} unless $a->{$_} }

      Note: that should probably be unless defined $a->{$_} so we don't remove false keys, but I made the choice to mirror the OP's syntax.

      <-radiant.matrix->
      Larry Wall is Yoda: there is no try{} (ok, except in Perl6; way to ruin a joke, Larry! ;P)
      The Code that can be seen is not the true Code
      "In any sufficiently large group of people, most are idiots" - Kaa's Law
Re: Shortcut operator for $a->{'b'}=$b if $b;
by merlyn (Sage) on Sep 20, 2005 at 16:33 UTC
      What's the for doing, there? Doesn't this work?

      $b and $a->{'b'} = $b

      edit: Doesn't solve the problem fully.

        foreach loops sets $_ to refer to the current value in the list which is being iterated. In this case, the list consists solely of $b.

        Your expression is equivalent, but it's not an acceptable answer since the question was about removing the need for using $b twice.

Re: Shortcut operator for $a->{'b'}=$b if $b;
by Codon (Friar) on Sep 20, 2005 at 16:35 UTC
    What is the correlation between 'b' and $b? Is one used to derive the other? If so, then map may help.
    $a = { map { $val = some_derivation($_) ? ( $_ => $val ) : () } qw(a b c) };
    Ivan Heffner
    Sr. Software Engineer, DAS Lead
    WhitePages.com, Inc.
      No correlation at all. This all started when I discovered the ||= operator, which test the assignee for truth, upon false assigns the assignor. I wanted to test the other side, and assign upon false.

      I think my answer is no.

        "assigns the assignor"? Every definition I can find for "assignor" defines it as the person (or in the case operator) who does the assignment. In other words, "=" is the assignor, not "$b".

        The standard terminology for assignments is "lvalue" for the variable receiving the value (which is usually on the *l*eft) and "rvalue" for the value being copied (which is usually on the *r*ight).

Re: Shortcut operator for $a->{'b'}=$b if $b;
by Roy Johnson (Monsignor) on Sep 20, 2005 at 16:46 UTC
    Something like
    { $a->{'b'} = do {$b or last} }
    might abort the assignment if $b is not true. I can't test it at the moment. Another idea that occurs to me is
    ($a->{'b'} = $b) or delete $a->{'b'};
    which expresses pretty directly what you said in your last sentence.

    Caution: Contents may have been coded under pressure.
      Tested. last does the trick.

      It doesn’t “abort” the assignment – the logical OR is evaluated first, then possibly the last, and if that is evaluated, it prevents the assignment from evaluating at all. And thus it works.

      Makeshifts last the longest.

        And thereby logical false values do not get assigned, which is not as per the specs.

        CountZero

        "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Shortcut operator for $a->{'b'}=$b if $b;
by polypompholyx (Chaplain) on Sep 20, 2005 at 17:24 UTC

    It's slightly OT, but you probably want to avoid using $a and $b (even as metasyntax), as they are used in sort code blocks. As such, they are exempted from strict checking, and could introduce subtle bugs.

Re: Shortcut operator for $a->{'b'}=$b if $b;
by radiantmatrix (Parson) on Sep 20, 2005 at 17:43 UTC

    You could abstract $b away into a sub (I'm assuming you're using it as a placeholder for a complex operation), and do something like:

    sub b { return $b; } b() and $a->{'b'} = b();

    I guess I don't really understand where your "way too verbose" is coming from; it would help if I could see a more involved example of the code you're attempting to simplify.

    <-radiant.matrix->
    Larry Wall is Yoda: there is no try{} (ok, except in Perl6; way to ruin a joke, Larry! ;P)
    The Code that can be seen is not the true Code
    "In any sufficiently large group of people, most are idiots" - Kaa's Law
Re: Shortcut operator for $a->{'b'}=$b if $b;
by dragonchild (Archbishop) on Sep 21, 2005 at 03:41 UTC
    No-one's mentioned using tie.
    package Tie::Hash::OnlyIf; sub STORE { my $self = shift; my ($key, $val) = @_; if ( $val ) { $self->{$key} = $val; } } package main; tie my %data, Tie::Hash::OnlyIf; $data{b} = $b;
    The only problem with this is that the casual reader will expect that the key 'b' will exist. But, it is a solution.

    Oh - and tie's a lot slower than normal hashes, but performance is almost always overvalued. Going from 0.01 to 0.08 seconds per execution isn't noticeable.


    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Shortcut operator for $a->{'b'}=$b if $b;
by rir (Vicar) on Sep 21, 2005 at 04:03 UTC
    { $hash{data} = $_ if defined ( local $_ = $something ); }

    A simple if-block is not to be faulted but if you are going to use a single statement a large $something should come last; else it will obscure following logic.

    With the above it is easy to forget to close a scope over the local.

    Be well,
    rir

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (5)
As of 2014-12-18 02:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (41 votes), past polls