Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable re-assign method result if not Nil

Is there idiomatic way of applying and assigning object variable method call, but only if it's defined (both method and the result)?

Like using safe call operator .? and defined-or operator //, and with "DRY principle" – using the variable only once in the operation?

Like this (but using another variable feels like cheating):

my $nicevariable = "fobar";

# key step
(my $x := $nicevariable) = $x.?possibly-nonexistent-meth // $x;

say $nicevariable;  # => possibly-nonexistent-meth (non-Nil) result or "foobar"

... And avoiding andthen, if possible.

like image 288
mykhal Avatar asked Jul 30 '21 20:07

mykhal


People also ask

How to reassign a variable if it is equal to null?

Use the nullish coalescing operator to reassign a variable if it's equal to null or undefined, e.g. myVar = myVar ?? 'new value'. The nullish coalescing operator returns the right-hand side operand if the left-hand side evaluates to null or undefined, otherwise it returns the left-hand side operand.

Can a variable be reassigned with a new value?

the variable can be reassigned with a new value, even a value of another type; the value, if it’s an array or an object, can be mutated. Knowing that both things are possible makes you think, every time you see pizza in the code, which value it has now. That’s a huge and unnecessary cognitive load that we should avoid.

Which method returns a result that is never used?

A COM or P/Invoke method that returns a HRESULT or error code that is never used. A language-integrated query (LINQ) method that returns a result that is never used.

What to do if a method does not return an error?

Or remove the call if it is unnecessary. If method A calls method B, but does not use the HRESULT or error code that the method returns, use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method.


4 Answers

Are you aware of the default trait on variables?

Not sure if it fits your use case, but $some-var.?unknown-method returns Nil, so:

my $nicevariable is default("fobar");
$nicevariable = $nicevariable.?possibly-nonexistent-meth;
say $nicevariable;  # fobar

results in $nicevariable being reset to its default value;

like image 127
dwarring Avatar answered Oct 19 '22 19:10

dwarring


I'm not entirely sure what you mean by "using the variable only once in the operation". If Liz's answer qualifies, then it's probably the cleaner way to go.

If not, here's a different approach that avoids naming the variable twice:

my $nicevariable = "foobar";
$nicevariable.=&{.^lookup('possibly-nonexistent-meth')($_)}

This is a bit too cryptic for my tastes; here's what it does: If the method exists, then that's similar to¹ calling &method($nicevariable), which is the same as $nicevariable.method. If the method does not exist, then it's like calling Mu($nicevariable) – that is, coercing $nicevariable into Mu or a subtype of Mu. But since everything is already a subtype of Mu, that's a no-op and just returns $nicevariable.

[1]: Not quite, since &method would be a Sub, but basically.

EDIT:

Actually, that was over-complicating things. Here's a simpler version:

my $nicevariable = "foobar";
$nicevariable.=&{.?possibly-nonexistent-meth // $_}

Not sure why I didn't just have that to begin with…

like image 26
codesections Avatar answered Oct 19 '22 19:10

codesections


Assuming the method returns something that is defined, you could do (if I'm understanding the question correctly):

my $x = "foobar";
$x = $_ with $y.?possibly-nonexistent-meth;

$x will remain unchanged if the method didn't exist (or it did exist and returned a type object).

like image 6
Elizabeth Mattijsen Avatar answered Oct 19 '22 17:10

Elizabeth Mattijsen


As of this merge you can write:

try { let $foo .= bar }

This is a step short of what I think would have been an ideal solution, which is unfortunately a syntax error (due to a pervasive weakness in Raku's current grammar that I'm guessing is effectively unsolvable, much as I would love it to be solved):

{ let $foo .?= bar } # Malformed postfix call...

(Perhaps I'm imagining things, but I see a glimmer of hope that the above wrinkle (and many like it) will be smoothed over a few years from now. This would be after RakuAST lands for Raku .e, and the grammar gets a hoped for clean up in Raku .f or .g.)


Your question's title is:

Variable re-assign method result if not Nil

My solution does a variable re-assign method if not undefined, which is more general than just Nil.

Then again, your question's body asks for exactly that more general solution:

Is there idiomatic way of applying and assigning object variable method call, but only if it's defined (both method and the result)?

So is my solution an ideal one?

My solution is not idiomatic. But that might well be because of the bug I found, now solved with the merge linked at the start of my answer. I see no reason why it should not become idiomatic, once it's in shipping Rakudos.

The potentially big issue is that the try stores any exception thrown in $! rather than letting it blow up. Perhaps that's OK for a given use case; perhaps not.


Special thanks to you for asking your question, which prompted us to come up with various solutions, which led me to file an issue, which led vrurg to both analyse the problem I encountered and then fix it. :)

like image 4
raiph Avatar answered Oct 19 '22 18:10

raiph