Refactoring conditional variable assignment - ruby

I'm working on a project. Currently I have a fairly large conditional statement, that assigns a value to a variable based on some input parameters. So, I have something like this.
if some condition
x = some value
elsif another condition
x = a different value
...
What's the best way to refactor this? I'm hoping that I might end up with something like
x = some value if some condition || another value if another condition
Is there a pattern for this sort of thing?

Just put the assignment outside the if.
x = if some condition
some value
elsif another condition
a different value
Or you could use a Hash.
x = dict[some condition]

It's not a pattern, but an operator. The one you're referring to is the ternary operator:
If Condition is true ? Then value X : Otherwise value Y
Here is an example:
speed = 90
speed > 55 ? puts("I can't drive 55!") : puts("I'm a careful driver")
Using the ternary statement is short, sweet, and does the job.

x = some condition ? some value :
another condition ? a different value : ...

A conditional statement is also an expression, so one of the first things you can do, if the variable is the same in each condition, is:
x = if cond1
expr1
elsif cond2
expr2
....
end
If the conditions are all states of a single expression, you can make this even neater, using a case statement.
However, the next most obvious re-factoring exercise is to get the big conditional isolated into a method, which should be fed the bare minimum data required to evaluate all the conditions and expressions.
E.g.
# Where conditional is currently, and x assigned, assuming the conditionals
# need a couple of variables . . .
x = foo param1, param2
# Elsewhere
private
def foo p1, p2
if cond1
expr1
elsif cond2
expr2
....
end
end

If you want to refactor for code clarity and flexibility, consider the replacing conditional with polymorphism refactor.
There's not enough detail in your question to go much further with recommendations, but this refactor will make your code base much more resistant to change. If you receive a new requirement, it's bad form to break open the conditional and modify it (more prone to introducing bugs, more difficult to do); it's preferable to create a new object that you can plug into the existing codebase. This flexibility what the Open/Closed Principle (the "O" in the SOLID acronym) describes.

Related

First assign and then reassign in if block as alternative to if-(else if)-else in Verilog

Is it better to first assign a value to a variable and then reassign in if block instead of using if-(else if)-else blocks where the assignment in if and else blocks are the same and the assignment in the else if block is a different assignment.
always #(*) begin
if condition1 begin
var = val1;
end
else if condition2 begin
var = val2;
end
else begin
var = val1;
end
end
vs
always #(*) begin
var = val1;
if condition2 begin
var = val2;
end
end
Given condition1 and condition2 are mutually exclusive, I am thinking that both of these blocks should synthesize the same logic and the choice of one over the other is purely aesthetic. Am I correct in thinking this or will one implementation synthesize differently from the other? If my thinking is correct, which method is preferred in the community?
Edit: Added mutually exclusive criteria after racraman's comment.
As for the general principle you're asking about: it doesn't matter which route you go. The synthesiser will be smart enough to work it out anyway. For simulation, it's possible that the option which carries out a default assignment first might execute more slowly (particularly if the assignment is a non-blocking one), but I wouldn't worry about it.
Personally, I prefer the second, because it's more obvious to the causual reader that you have covered your bases in terms of generating unwanted latches (in other words, you are always assigning to var).
Having said all that, your example is (in principle) very simple, and in this particular case it's obvious that a mux is required, and you probably don't need an always block at all, and should just use an assign with a ternary operator.
I say 'in principle' because you logic doesn't really make sense. You say your conditions are mutually exclusive, but what happens if neither condition is active? Do you actually need a latch to preserve the previous output? If not, why do you have two conditions at all?
While using always#(*) blocks you may end up inferring unintentional latches in your design.
For assignments of the type you have mentioned its better to go for ternary operators.
assign var = (cond1)?(val1):(cond2)?(val2):(val1);
//Assuming cond1 and cond2 are mutually exclusive
If cond1 and cond2 can occur at the same time then above assign can be changed as
assign var = (cond1 && cond2)?(val1):(cond1)?(val1):(cond2)?(val2):(val1);
//Assuming val1 when both cond1/2 are high

Will `&&` always run before `if` on the same line in Ruby

Will every && run before if on the same line in Ruby?
For example:
#building.approved = params[:approved] if xyz && abc && mno...
Can an unlimited number of && be used on the right side of an if without using parentheses?
I'm inclined to use parentheses but I'd like to understand the default behaviour.
Everything after the if must be part of the condition by virtue of the syntax. The only way to get around this is to be really specific:
(#building.approved = params[:approved] if xyz) && abc && ...
Which is obviously not what you're intending here.
Operator binding strength isn't an issue here since if is a syntax element not an operator, so it has the absolute lowest priority.
The only conditions that will be evaluated are the ones that produce a logically false value, or come after one that was logically true as the first one to return logically false will halt the chain.
That is:
if a && b && c
Will stop at a if that is a logically-false value. b and c will not be evaluated. There's no intrinsic limit on chaining though.

Complex IF THEN statements in VB6 [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Does VB6 short-circuit complex conditions?
I am curious about how IF statements are executed in VB6.
For example if I have the statement
If x And y Then
'execute some code
End If
Does the code move on if x is not true? Or does it go ahead and evaluate y even though there is no logical point?
Another example
If x Or y Then
'execute some code
End If
Does the code continue and evaluate y if x is true?
EDIT:
Is there a way to avoid nested IF statements if I want to evaluate very complex conditions and I don't want to waste CPU time?
What you are describing is short circuiting logic, and VB6 doesn't have it...
For example, in VB.Net you might write
If x AndAlso y then...
In this case y is not tested if x turns out to be false.
In your VB6 example, you'll get a Object or With block variable not set error if you try something such as:
Dim x as Object
If Not x Is Nothing And x.y=1 Then
Since object x has not been instantiated.
An unwieldy or-like statement that exhibits short circuiting behaviour:
select case True
case a(), b(), c()
'//if a returns true b & c are not invoked, if b returns true a & b were invoked
case else
...
To answer your edit - avoiding nested IF statements, you can use Select Case, covered in the latter half of this article.
Code snippet from the article:
Select Case strShiftCode
Case "1"
sngShiftRate = sngHourlyRate
Case "2"
sngShiftRate = sngHourlyRate * 1.1
Case "3"
sngShiftRate = sngHourlyRate * 1.5
Case Else
Print "Shift Code Error"
End Select

Ruby: Assign output of a function only if it does not return nil

When programming in Ruby I quite often have assignments like the following
test = some_function if some_function
With that assignments I want to assign the output of a function, but if it returns nil I want to keep the content of the variable. I know there are conditional assignments, but neither ||= nor &&= can be used here. The shortest way I found to describe the statement above is
test = (some_function or test)
Is there a better / shorter way to do this?
I don't think there's anything better than the last snippet you showed but note that or is used for flow control, use || instead:
test = some_function || test
It's usually better to assign new values to new names, the resulting code is easier to understand and debug since variables/symbols have the same value throughout the scope:
some_different_and_descriptive_name_here = some_function || test
I'd just add parentheses
(a = b) unless b.nil?
(a = b) if b
being inferior because if b is false then a remains as before
Keep in mind that this evaluates b twice, so if b is a function with side-effects (such as changing variables outside of its scope or printing) it will do that twice; to avoid this you must use
temp = b; (a = temp) unless temp.nil?
(which can, of course, be split into)
temp = b
(a = temp) unless temp.nil?

Is it better to use NOT or <> when comparing values?

Is it better to use NOT or to use <> when comparing values in VBScript?
is this:
If NOT value1 = value2 Then
or this:
If value1 <> value2 Then
better?
EDIT:
Here is my counterargument.
When looking to logically negate a Boolean value you would use the NOT operator, so this is correct:
If NOT boolValue1 Then
and when a comparison is made in the case of the first example a Boolean value is returned. either the values are equal True, or they are not False. So using the NOT operator would be appropriate, because you are logically negating a Boolean value.
For readability placing the comparison in parenthesis would probably help.
The latter (<>), because the meaning of the former isn't clear unless you have a perfect understanding of the order of operations as it applies to the Not and = operators: a subtlety which is easy to miss.
Because "not ... =" is two operations and "<>" is only one, it is faster to use "<>".Here is a quick experiment to prove it:
StartTime = Timer
For x = 1 to 100000000
If 4 <> 3 Then
End if
Next
WScript.echo Timer-StartTime
StartTime = Timer
For x = 1 to 100000000
If Not (4 = 3) Then
End if
Next
WScript.echo Timer-StartTime
The results I get on my machine:
4.783203
5.552734
Agreed, code readability is very important for others, but more importantly yourself. Imagine how difficult it would be to understand the first example in comparison to the second.
If code takes more than a few seconds to read (understand), perhaps there is a better way to write it. In this case, the second way.
The second example would be the one to go with, not just for readability, but because of the fact that in the first example, If NOT value1 would return a boolean value to be compared against value2. IOW, you need to rewrite that example as
If NOT (value1 = value2)
which just makes the use of the NOT keyword pointless.

Resources