Refactor Default Or Else

Or else what? Hmmf, I don't have to refactor nuthin'.


[CategoryRefactoring/RefactoringLanguage]

You can sometimes simplify conditional logic by "defaulting" to a common result, and then expressing only the deviations from the default in logic:

Private Sub RefactorDefaultOrElse()

From this...

    If Condition() Then
        lvar = Value()
    Else
        lvar = Default()
    End If
to this...
    lvar = Default()
    If Condition() Then
        lvar = Value()
    End If

It's better to set a default value first if the conditional logic to set the variable is complex. This ensures that you don't end up with an unintialized or improperly initialized variable.

It's not obvious to me why the latter form is safer or more intuitive. Perhaps the example is too simple?

It's better to use the "else ... default" form if the default is complex or expensive to compute.

If both conditions apply, use a flag:

    bUseDefault = True 
    If Condition() Then 
        lvar = Value() 
        bUseDefault = False 
    End If 
    If bUseDefault Then 
        lvar = Default() 
    End If 
(This is way overkill for the simple example given. ;-)

End Sub


Example, pulled from RefactorNegateIf:

Here's an example refactoring, where using the "Refactor Negative IF" rule improved the code:

From...

    If ConditionOne?() And ConditionTwo?() Then
        X = 1
    Else
        X = 2
    End If

If ConditionOne?() And ConditionThree?() Then Y = 1 Else Y = 2 End If
to...
    X = 2
    Y = 2

If ConditionOne?() Then If ConditionTwo?() Then X = 1 End If If ConditionThree?() Then Y = 1 End If End If
(It also helps that "ConditionOne?()" is a really strange and unusual condition: The "<var> = 2" lines are the normal business rules, while the "<var> = 1" lines are exceptions/overrides.)

Thus, we end up saying...

-- JeffGrigg

Of course, if this block of code is the only code in the body of a method, you can convert if ConditionOne?() to a GuardClause. (if not ConditionOne?() then return end if)


On a somewhat related note, I'm quite a fan of the form that you'd more often see in functional programming. The idea it instead of using several branches, each of which having the side-effect of initialising the variable, you have a single assignment which sets the variable to the result of some expression. For example, in pseudo code:

 X = if (Condition)
         value1;
     else
         value2;

I find this form quite nice, because it makes it obvious that your variables are all initialised. Unfortunately to factor things like this in C-style languages I suspect you'd often need to make new functions, which might be inconvenient for a lot of simple cases. -- LukeGorrie

Not necessarily. C does have the ?: conditional expression evaluation operator, after all.

That's true, but I still suspect you'd need to go to functions pretty often, good though ?: is for an 'if-else' form. Consider some erlang code which would seemingly need to be function'ified in C: (admittedly its politely asking for function'ification in Erlang too - perhaps I should revise the example if that's a bother)

 Threads = case Argument of
               a_few       -> 1;
               a_fair_few  -> 5;
               quite_a_lot -> 10
          end,

As a side-note, another thing I love about that form is that the code is only defined for a few special atoms - i.e., there's no "default", so it's undefined for nonsensical arguments. I hate it when I find a bogus value in my code, only to see that it's hopped half way across my program from its source by slipping through defaults and so forth. Java null references spring to mind. -- LukeGorrie

C/C++:

 X = Condition ? value1 : value2;
 Threads = a_few ? 1 : a_fair_few ? 5 : quite_a_lot ? 10 : -1;

VisualBasic:
 X = IIf(Condition, value1, value2)
 Threads = IIf(a_few, 1, IIf(a_fair_few, 5, IIf(quite_a_lot, 10, -1)))
If "Threads" is a Variant, then you could use "Nothing" instead of "-1", or other arbitrary value.

This might be clearer if you use the Choose function. This function has the following syntax:

 Choose(condition1, value1, condition2, value2, ..., conditionN, valueN)

Each condition is evaluated, moving left to right, and the first one that evaluates to True causes the corresponding value to be returned. So you could write:
 x = Switch(argument = a_few, 1, argument = a_fair_few, 5, argument = quite_a_lot, 10)

The biggest drawback is that there is no short-circuiting - all conditions are evaluated.


 X = if (Condition)
         value1;
     else
         value2;

... in a real functional language is:

 operation_on_x (condition_foobar Condition
    where 
      condition_foobar true is
        value1
      condition_foobar false is
        value2
   )

... or something like that

-- AluoNowu (nov17-01)


EditText of this page (last edited November 18, 2001) or FindPage with title or text search