How can I automatically replace the ternary operator by if/else? - refactoring

Sometimes I get some very ugly code which uses the ternary operator too often. I would like to be able to detect such ternary operators:
statement ? if-block : else-block;
and replace them by
if (statement) {
if-block
} else {
else-block
}
If solution should work with Java.

Related

Difference between if as an expression and if as a statement

So I was watching this video on the Go language - https://www.youtube.com/watch?v=p9VUCp98ay4 , and at around 6:50 a guy asks a question about why they implemented if's as statements and not expressions. What is the difference between those two implementations? As far as I know, I've never had to change the way I use a conditional based on the language.
Edit: and what does he mean that "you need values rather than variables" in his question?
The difference between expressions and statements is that expressions produce a value and thus can be used in places where values are required. So expressions can be used as values for variables, arguments to functions or operands to operators. Statements can't.
and what does he mean that "you need values rather than variables" in his question?
I assume that by vals he means constants (which are called vals in Scala for example).
If if were an expression, you could do this:
const myValue = if condition { value1 } else { value2 }
Since if is not an expression, you have to do this:
var myValue
if condition {
myValue = value1
} else {
myValue = value2
}
So you needed to make your variable mutable (use var instead of const), which is what the person asking the question likely meant.
You can get the same code elegance that you would get from if expression by using an instantly invoked function (IIF) combined with if statements in GO. I'm not a GO programmer (mainly typescript) so please let me know if this is bad for performance for any reason.
func main() {
amIHungry := true
didMyPaycheckComeInYet := false
choice := func() string {
if(!amIHungry && !didMyPaycheckComeInYet){
return "stay-home"
}
if(!amIHungry && didMyPaycheckComeInYet){
return "buy-new-keyboard"
}
if(amIHungry && !didMyPaycheckComeInYet){
return "make-ramen"
}
return "taco-bell-time"
}()
println(choice)
}
and then later on in your program, rather than having a bunch of out of context states, you can have a simplified "choice" to choose your app logic.
if(choice == "taco-bell-time"){
println("Order a bean burrito, but with black beans,")
}
is a little easier to reason about than
if(amIHungry && didMyPaycheckComeInYet){
println("Order a bean burrito, but with black beans,")
}

Mixing mathematical expression with control flow

I would like to know, how expressions are parsed when are mixed with control flow.
Let's assume such syntax:
case
when a == Method() + 1
then Something(1)
when a == Other() - 2
then 1
else 0
end
We've got here two conditional expressions, Method() + 1, Something(1) and 0. Each can be translated to postfix by Shunting-yard algorithm and then easily translated into AST. But is it possible to extend this algorithm to handle control - flow also? Or are there other approaches to solve such mixing of expressions and control flows?
another example:
a == b ? 1 : 2
also how can I classify such expression: a between b and c, can I say that between is three arguments function? Or is there any special name for such expressions?
You can certainly parse the ternary operator with an operator-precedence grammar. In
expr ? expr : expr
the binary "operator" here is ? expr :, which conveniently starts and ends with an operator token (albeit different ones). To adapt shunting yard to that, assign the right-precedence of ? and the left-precedence of : to the precedence of the ?: operator. The left-precedence of ? and the right-precedence of : are ±∞, just like parentheses (which, in effect, they are).
Since the case statement is basically repeated application of the ternary operator, using slightly different spellings for the tokens, and yields to a similar solution. (Here case when and end are purely parenthetic, while then and the remaining whens correspond to ? and :.)
Having said that, it really is simpler to use an LALR(1) parser generator, and there is almost certainly one available for whatever language you are writing in.
It's clear that both the ternary operator and OP's case statement are operator grammars:
Ternary operator:
ternary-expr: non-ternary-expr
| non-ternary-expr '?' expr ':' ternary-expr
Normally, the ternary operator will be lower precedence from any other operator and associate to the right, which is how the above is written. In C and other languages ternary expressions have the same precedence as assignment expressions, which is straightforward to add. That results in the relationships
X ·> ?
? <· X
? ·=· :
X ·> :
: <· X
Case statement (one of many possible formulations):
case_statement: 'case' case_body 'else' expr 'end'
case_body: 'when' expr 'then' expr
| case_body 'when' expr 'then' expr
Here are the precedence relationships for the above grammar:
case <· when
case ·=· else
when <· X (see below)
when ·=· then
then ·> when
then ·> else
else <· X
else ·=· end
X ·> then
X ·> when
X ·> end
X in the above relations refers to any binary or unary operator, any value terminal, ( and ).
It's straightforward to find left- and right-precedence functions for all of those terminals; the pattern will be similar to that of parentheses in a standard algebraic grammar.
The Shunting-yard algorithm is for expressions with unary and binary operators. You need something more powerful such as LL(1) or LALR(1) to parse control flow statements, and once you have that it will also handle expressions as well. No need for the Shunting-yard algorithm at all.

Inline if with else

I realize that it's not valid ruby but what would be the technical hurdles to implement the below functionality into the Ruby core language (of say v2.3)?
variable = 1 if condition else -1
I'd also like to allow the following for more generic use.
variable = { 1 } if condition else { -1 }
I'm very open to requiring an "end" at the end.
I get that a ternary can easily accomplish this but I'm looking for a more readable inline-if that allows an else.
I get that I can make a function which does this via any number of styles but I'd prefer to have it as readable as possible.
Thanks.
EDIT: I hate editing questions for obvious reasons.
In response to the question of how the generic option is more ruby-esque, see the below example (I needed newlines).
variable = {
operation_one
operation_two
...
SUCCESS_STATUS_CODE
} if loaded_dependencies else {
do_detailed_logging
FAILURE_STATUS_CODE
}
if variable then
it_worked
else
explain_why
end
Because your example, while it seems readable to you, has too many ambiguities in other cases.
Not to mention that ruby has a way to do this, and it's the ternary operator. To say that your example is more ruby-like, is almost like wondering why the wheelbase of the Ford Mustang wasn't longer, and that it would be more "Mustang-like" if it was.
But here are some issues with your proposal, starting from your example:
variable = { 1 } if condition else { -1 }
Here you've given your "if else" bit a lower precedence than the "=".
In other words:
variable = ({ 1 } if condition else { -1 })
That's a serious problem, because it breaks the currently allowed:
variable = 1 if condition
The precedence for that statement is:
(variable = 1) if condition
And that's important. No assignment happens if the condition is false.
This can be a really big deal, for example if the lvalue (left side) actually has side-effects. For example:
var[0] = 1 if condition
The lookup for "var[0]" is a method in whatever class object var is, and while [] doesn't usually have side-effects, it can - and now you are going to do those side effects even if the condition is false.
And I won't even get into:
variable = { 1 } if condition if condition2 else { -1 }
But if you don't like it, you can always write your own language and see what happens!

Is there difference in processing time between multiple if statement and one if with multiple condition?

I prefer to avoid nested if but I wonder if there's time difference between these two :
if(a && b)
{
...
}
or
if(a)
{
if(b)
{
...
}
}
They're exactly identical.
However it depends on your compiler , you have not mentioned the language you will be using.
But most of the compiler will interpret these both code into same thing
example for java
Should if(a&&b) take more time than if(a) if(b)?
example for c++
Nested if statements and "&&" operator
It is the same.
After a gives true in (a && b && c && ...), b is tested, then c and so on – one by one until some expression in chain will result false. After it happens all subsequent expressions will be skipped. As far as I know it works the same way in all C-like languages.
Your code will be more readable if you use && operator instead of nesting many if blocks.

Expressions in control statements

I've never used the following kind of expressions in if statements or other control structures (example in PHP):
if ( ( $p = someFunction() ) !== false ) {
// Use $p
}
I usually take this kind of assignment expression out and have it evaluated before I check it in an if statement.
My questions are:
Is there a name for this technique?
After the assignment ($p = someFunction()) what types can be tested for? (For example only true/false or the actual type someFuntion returns)?
Is this reccomended and safe to use with most languages and to expect similar behaviour?
You could name it using return value of assignment expression?
Why do you ask this generally? You have to check if your language supports this kind of code. Most C like languages return the value that is assigned to the variable on the left so it can be any type.

Resources