May 2003
The Dynamic Dispatch Problem
Introduction
Dynamic dispatch, specifically dispatched based on parameter types, introduces unintuitive side effects in the context of importing other projects or libraries. This document describes the problem, and will hint at a solution.
A project is a set of objects and interfaces. When importing existing projects for use with a current task, the user expects these objects and interfaces to perform as specified. Unfortunatly, the existence of dynamic dispatch allows the user to unknowingly change those specifications!
Example Problem
The problem arises when there are two different programmers responsible for two different class definitions; one built using the other. In the example below, the base class A has two methods that are so similar it serves the first programmer to implement one with the other. The symmetry of the problem makes the decision of which to implement realWork() arbitrary. When class A belongs to an imported project, we should not expect the programmer of B to know about the implentation of A.
CLASS A
METHOD setRange(start AS Integer, end AS Integer)
setRangeLength(start, end-start);
END setRange
METHOD setRangeLength(start AS Integer, length AS Integer)
realWork(start, length);
END setRangeLength
END A
CLASS B EXTENDS A
METHOD setRangeLength(start AS Integer, length AS Integer)
setRange(start, start+length);
END setRangeLength
END B
There is a dynamic dispatch loop created in this senario that neither the programmer of A or programmer of B should expect:
Assuming we call setRangeLength() on an object of dynamic type B we have:
B.setRangeLength() calls A.setRange()
A.setRange() calls B.setRangeLength() (because of dynamic dispatch)
B.setRangeLength() calls A.setRange()
and so on...
Does this ever Happen?
- java.awt.Component.setBounds(int x, int y, int width, int height) does real work
- java.awt.Component.setLocation(int, int) calls setBounds()
- java.awt.Component.setSize(int, int) calls setBounds()
In a limited dispatch language like Java, the chances of this happening are slim. But full dynamic dispatch would enable many more opportunites for this to become a problem.
In the 90s Java AWT sucked, Swing was buggy, and I learned all about the Dymanic Dispatch Problem. I had to make some specialized window Components. After a hellish debugging session, this is what I found:
Of course, my application overrode setBounds() which called both setLocation() and setSize(), creating an infinite loop. Java's documentation does not cover this "gottcha".
Reasons for the Problem
We have a few potential suspects that are responsible for creating this loop.
- The fact that class A is using dynamic dipatch from setRange() to setRangeLength(): The programmer of A should have made this a direct method invocation instead. Yet this solution creates its own problems: A's test suite may work perfectly fine on class A as written above, how can we expect A's programmer to know there is an error in the specification of A?
- B.setRangeLength() is calling A.setRange(): The mear fact that B is calling a method of A is one cause of the problem. We could have the B's programmer indicate this call as immune to dynamic dispatch.
A.setRangeLength() is not "final": Preventing A.setRangeLength() from being overridden prevents B.setRangeLength() from ever existing. In general, all methods that are called should be declared "final", but this is an extreme that inhibits inheritance.- Dynamic dispatch is allowed across project boundaries: By indicating that A belongs to a different project we can disallow dynamic dispatch across the project boundary. This option may be too harsh because there could be situations that this dymanic dispatch is good.
- Complier gives no warnings: We can blame the compiler for not identifying the logical loop created by the two classes. Identification can flag the suspects and have B's programmer change his use of A's methods, specifically call setRangeLength() instead of setRange(). But how can the compiler tell the difference between intended recursion and these unintended loops?
Solutions
For now the DBOS compiler will warn of any dynamic dispatch dependent loops.
May 7, 2003: Revisions and formatting
Februray 22, 2003: First writing
April 10, 2003: Clarified and formatted