Software Design/Avoid a variable called "result"

From Wikiversity
Jump to navigation Jump to search

Checklist questions:

  • The variable returned from a function has a more meaningful name than just result (res, retVal, toReturn, etc.)?
  • Is it possible to return early from a function instead of creating a "result" variable?

Why[edit | edit source]

Calling a variable result is equivalent to not calling a variable at all because "result" doesn't bear any meaning. The benefits of semantic variable naming are forgone.

When reading through the function down to the final statement like return result, people have to remember what type of value the function should return instead of just seeing that. The function's name may not embed the full information about the returned type: for example, a function getDiscountPlatinumLoyalityForAccessories(): Double doesn't encode in its name whether the returned discount is a percent or a value between 0 and 1 because the name is already very long. In this case, a reader should consult the function's documentation every time they want to recall what type of value the function should return. If the documentation doesn't specify that or is absent, this semantic information is completely lost in the code. Thus, a return variable called result contributes to cognitive load. The code is less obvious and makes readers navigate more.

When the result variable has a semantic name it may also reduce the probability of making a mistake in the function, for example, by assigning a value in the wrong units to the variable. Consider this function:

// A function with a bug
fun getDiscountPlatinumLoyalityForAccessories(): Double {
  var result = Loyality.PLATINUM.discountPercent
  if (christmasDiscountSeason) {
    result += CHRISTMAS_DISCOUNT_DECIMAL
  }
  if (specialDiscountsForAccessories) {
    result += SPECIAL_ACCESSORIES_DISCOUNT_DECIMAL
  }
  return min(result, MAX_DISCOUNT_DECIMAL)
}

It would be easier to spot the bug in this function if the variable was called discountDecimal and the first line was

  var discountDecimal = Loyality.PLATINUM.discountPercent

Why not[edit | edit source]

When a function is short, or when the result type doesn't have units, semantic naming of the result variable makes little or no difference. On the other hand, in the presence of a variable called result, it's harder to make a mistake by accidentally returning another variable from the function, especially if calling variables to be returned from functions result is a convention which is followed consistently in the codebase. See practice Call function's return variable "result".

Combining the approaches[edit | edit source]

A compromise solution is to call functions' result variables resultSemanticName, for example, resultDiscountDecimal in getDiscountPlatinumLoyalityForAccessories() function above.

Removing a result variable altogether[edit | edit source]

Sometimes, a result variable can be eliminated by returning early from a function. Consider this function:

fun remove(list: MyList, elemToRemove: Elem): Boolean {
  var result = false
  var iterElem: Elem? = list.first()
  while (iterElem != null) {
    if (iterElem == elemToRemove) {
      iterElem.remove()
      result = true
      break;
    }
    iterElem = iterElem.next()
  }
  return result
}

It doesn't make much difference whether the result variable is called result or removed here. However, the variable can be eliminated altogether to make the function shorter and simpler:[1]

fun remove(list: MyList, elemToRemove: Elem): Boolean {
  var iterElem: Elem? = list.first()
  while (iterElem != null) {
    if (iterElem == elemToRemove) {
      iterElem.remove()
      return true
    }
    iterElem = iterElem.next()
  }
  return false
}

A result variable is often a sign that such simplication is possible.

Static enforcement[edit | edit source]

Checkstyle (Java)[edit | edit source]

LocalVariableName and LocalFinalVariableName modules:

<module name="LocalVariableName">
  <property name="format" value="(?i)^(?!result$|retValue$|retVal$|ret$|res$|r$).*"/>
</module>
<module name="LocalFinalVariableName">
  <property name="format" value="(?i)^(?!result$|retValue$|retVal$|ret$|res$|r$).*"/>
</module>

Related practices[edit | edit source]

References[edit | edit source]

  1. Boswell, Dustin; Foucher, Trevor (2011). The Art of Readable Code. ISBN 978-0596802295.  Chapter 9, section "Eliminating Intermediate Results"