Thou shalt not bind prematurely
In contrast to the previous example, there are cases where one wants to have the same name used for different operations. Consider, for example, the display operation: it takes an object as input and displays it on the screen. Depending on the type of the object, we want to use different display mechanisms. If the object is a picture, we want it to appear on the screen. If the object is a person, we want some form of a tuple printed. Finally, if the object is a graph, we will want its graphical representation. Consider now the problem of displaying a set, the type of whose members is unknown at compile time.
In an application using a conventional system, we have three operations: display-person, display-bitmap and display-graph. The programmer will test the type of each object in the set and use the corresponding display operation. This forces the programmer, to be aware of all the possible types of the objects in the set, to be aware of the associated display operation, and to use it accordingly.
for x in X do begin case of type(x) person: display(x); bitmap: display-bitmap(x); graph: display-graph(x); end end
In an object-oriented system, we define the display operation at the object type level (the most general type in the system). Thus, display has a single name and can be used indifferently on graphs, persons and pictures. However, we redefine the implementation of the operation for each of the types according to the type (this redefinition is called overriding). This results in a single name (display) denoting three different programs (this is called overloading). To display the set of elements, we simply apply the display operations to each one of them, and let the system pick the appropriate implementation at run-time.
for x in X do display(x)
Here, we gain a different advantage: the type implementors still write the same number of programs. But the application programmer does not have to worry about three different programs. In addition, the code is simpler as there is no case statement on types. Finally, the code is more maintainable as when a new type is introduced as new instance of the type are added, the display program will continue to work without modification. (provided that we override the display method for that new type).
In order to provide this new functionality, the system cannot bind operation names to programs at compile time. Therefore, operation names must be resolved (translated into program addresses) at run-time. This delayed translation is called is called late binding.
Note that, even though late binding makes type checking more difficult (and in some cases impossible), it does not preclude it completely.