Clean Code: typedef’s

Description

We describe why and how to use typedef‘s in C++ development with examples from ITK.

Why typedef Usage is Important

Reason Number 1: Maintainability

Using typedef‘s instead of explicit types is analogous to using variables instead of explicit numbers in your code. If the type used for a certain purpose need to be changed, then only the typedef line needs to be changed. If typedef’s are not used, thousands of manual changes to the code may be required to achieve this simple logical operation.

This advantage of typedefs becomes increasing important when dealing with complex types that are defined in terms of simple types in a nested way. This is common with advanced data structures and templated code.

By abstracting types, typedefs can also decimate the number of characters to type when coding, which reduces development time.

Reason Number 2: Readability

C++ is a strongly typed language. While this increases the verbosity of the language, it also provides an opportunity to create more readable code if the names of the types lend insight into the meaning and intended use of a type.

A typedef also allows types to be collected into higher-level abstractions. This eases logical comprehension.

How to Use typedef’s to Improve Software Quality

Best Practices

Standard naming conventions for typedef’s defined within a class allow for reuse in templated applications. Some of the standard typedef’s defined for all ITK classes are Self, Superclass, Pointer, and ConstPointer.

Use a typedef for each new type created in the code made from a template. Give the typedef a meaningful, succinct name.

Sometimes, typedefs should also be created for simple types. Again, a uniquely identifiable, meaningful name for a type increases maintainablity and readability.

Exercise

Improve the following code by using typedef’s:

itk::ImageFileReader< itk::Image< unsigned char, 2 > >::Pointer reader =
  itk::ImageFileReader< itk::Image< unsigned char, 2 > >::New();
reader->SetFileName( argv[1] );

itk::GradientMagnitudeImageFilter< itk::Image< unsigned char, 2 >,
  itk::Image< float, 2 > >::Pointer edgeStrengthFilter =
  itk::GradientMagnitudeImageFilter< itk::Image< unsigned char, 2 >,
    itk::Image< float, 2 > >::New();
edgeStrengthFilter->SetInput( reader->GetOutput() );

itk::ImageFileWriter< itk::Image< float, 2 > >::Pointer writer =
  itk::ImageFileWriter< itk::Image< float, 2 > >::New();
writer->SetFileName( argv[2] );
writer->SetInput( edgeStrengthFilter->GetOutput() );
writer->Update();

Answer:

const unsigned int Dimension = 2;

typedef unsigned char                            InputPixelType;
typedef itk::Image< InputPixelType, Dimension >  InputImageType;

typedef float                                    OutputPixelType;
typedef itk::Image< OutputPixelType, Dimension > OutputImageType;

typedef itk::ImageFileReader< InputImageType >  ReaderType;
ReaderType::Pointer reader = ReaderType::New();
reader->SetFileName( argv[1] );

typedef itk::GradientMagnitudeImageFilter<
    InputImageType, OutputImageType >  EdgeStrengthFilterType;
EdgeStrengthFilterType::Pointer edgeStrengthFilter = EdgeStrengthFilterType::New();
edgeStrengthFilter->SetInput( reader->GetOutput() );

typedef itk::ImageFileWriter< OutputImageType > WriterType;
WriterType::Pointer writer = WriterType::New();
writer->SetFileName( argv[2] );
writer->SetInput( edgeStrengthFilter->GetOutput() );
writer->Update();

Video