Monday, 6 January 2014

Guideline #2. Make all type conversions explicit

Guideline

Assignments, function calls and expressions in general should not contain implicit type conversions. All type conversions should be explicit.

Type conversions should be isolated in their own line, which should consist only of the assignment of the result of the type conversion to a variable of the target type.

A statement should not mix type conversion with other operations. For example, if you need to convert an object to one of another type to pass it as a function parameter, do not do it in the function call itself; instead, do it in a separate instruction in the previous line.

Discussion

Type conversion occurs when an entity of type A is, well, converted to an entity of type B. This may occur in one of these circumstances:
  • Using the object as a parameter in a function call, where the type of the parameter in the function is not the same as the type actually passed to it.
  • Using the object as an operand in an expression which requires an object of a different type.
  • Assigning the object to an object of a different type.
In many cases this operation will be impossible. If a function takes a Customer, for example, you cannot call it with a totally unrelated type such as a Printer. In other cases the conversion may be possible but involve some risks. Finally, there may be cases in which it can be done safely.

A type conversion may be implicit or explicit. An explicit type conversion is one which you can read in the code. An implicit type conversion is one which does not appear in the source code, but is done automatically when the software is executed.

Making all type conversions explicit, as this guideline states, helps you to identify the potentially dangerous ones. Type conversions shouldn't be spread all over your code, because good design techniques should avoid them in most cases. In such specific cases where a type conversion is needed, it's better to make it shine out so that more coding, review and testing effort is dedicated to ensure its correctness.

Example

Don't

int i = 0;
double d = 10.0;

(…)

i = d;

This intentionally simple example is enough to show my point. There are always several things in each piece of code that might potentially go wrong, and one of them in this case (converting a value from one type to another) is totally hidden in the assignment expression, so that an error in it might go unnoticed.

Do

int i = 0;
double d = 10.0;

(…)

i = static_cast<int>(d);

The type conversion is made explicit by means of a cast instruction. That is precisely the meaning of a cast: an explicit type conversion.

C++ offers several cast instructions, namely static_castdynamic_castreinterpret_cast. and const_cast. They are the equivalent of a warning sign in a road. They tell the reader of the code that something might go wrong because of the type conversion. It won't go wrong, because you designed and tested it well - but the potential risk is there. Something's going on which shouldn't be hidden, for the sake of today's and tomorrow's correctness.

If you get used to always respect the types of your objects, identify the occasional type conversions and make them explicit, you will prevent some common mistakes and avoid future problems.

Bibliography

This materials referenced in this section discuss the issue described above in more detail. The range they cover is much wider, though, and dives into more depth. See the page Bibliography for the detailed references.

[MEYERS 1998-1] The new forms of cast are discussed in the Introduction, pages 10-11. Implicit type conversions are treated on pages 67, 83, 85 and 86.

[MEYERS 1998-2] Implicit type conversions are central to the subject of Item 5: "Be wary of user-defined conversion functions", pages 24-31.

[SUTTER 1999] Implicit type conversions appear on pages 19, 70, 164-165 and 191. See especially Item 39: "Automatic conversions".

No comments:

Post a Comment