- A flexible dispatching framework |
This web page collects information and files related to PolyD, a dispatching framework for Java developed in the context of the Ovm project at Purdue University. PolyD is a pure Java tool that, using dynamic bytecode generation, allows the user to define customized dispatching policies, altering many aspects of message dispatching that are usually predermined and that cannot be easily changed. In simpler words, using PolyD you can define a set of methods and invoke them according to user-defined criteria. For example, PolyD can be used to implement a visitor-like mechanism, or general multiple dispatching, or more unusual dispatching policies. PolyD makes it possible to personalize many aspects of the dispatching process: the handling of null arguments, of missing methods, of ambiguities, of the method invocation, and so on. In that respect, PolyD is a more general and flexible solution to the "expression problem" than other tools. As an added advantage, PolyD is a pure Java tool that does not require special syntax, special bytecode, preprocessors, or custom VMs. The performance of the tool is well-suited to real-life applications: for unary methods PolyD has performance similar, or even better, than the Runabout and the Sprintabout, for other arities we find that PolyD scales better than MultiJava and JMMF. Update: Dispatchers can now be even more general! Additional values can be used to perform the method selection, besides the dynamic class of the message arguments. Non-caching dispatchers are now also supported. Please read the updated manual for more information.
Let's assume that we want to describe the effect of a Person dancing in a given Place. For this example we will use multiple dispatching, although a different policy could be used. First of all, we need an interface: @ PolyD @ DispatchingPolicy (MultiDisp.class) interface Dance { void dance(Person p,Place q); } Using PolyD we can decouple the interface from the actual implementation, and combine the two at a later stage. This is the implementation that we will be using in our example: class Impl { void dance(Dancer p, Stage q) { printComment("Dance is an expression of art!"); } void dance(Person p, Stage q) { printComment("What is that guy doing on the stage?"); } void dance(Person p, Place q) { printComment("That person is dancing. Strange."); } } The code, quite simple, describes the most appropriate response to combinations of different kinds of Persons and Places. We can now test our dispatcher: Person nureyev = new Dancer(); Person joe = new Person(); Place bolshoi = new Stage(); Place office = new Place(); Dance d = PolyD.build(Dance.class,new Impl()); d.dance(joe,bolshoi); d.dance(nureyev,bolshoi); d.dance(nureyev,office); In all three cases the arguments to dance() are statically a Person and a Place, but nothing more specific. The dispatcher uses the real dynamic class of the arguments to find the most appropriate method. If we want to replace multiple dispatching with another dispatching policy, overloading for instance, we can create a new interface specifying @DispatchingPolicy (Overloading.class) instead. The two interfaces can also share a common superinterface, allowing the same client code to be tried using different dispatching policies, as shown in this example.
PolyD allows dispatching on an arbitrary number of receivers, return values are supported as are primitive types. Multiple bodies can be specified with a single interface, offering a "mix-in"-like structure: Dance d = PolyD.build(Dance.class,body1,body2,body3); All of the methods available in the various bodies will be combined to satisfy the prototypes declared in the interface. It is also possible to share one body among multiple dispatchers, and to call the same group of methods using different names. The standard dispatching policies available are multiple dispatching, overloading, and a "non-subsumptive" policy that only calls a method if the classes of the arguments match exactly those of the method parameters. It is possible to define personalized dispatching policy using a simple API. The multiple dispatching policy also implements a form of symmetric multiple inheritance, treating equally interfaces and classes (MultiJava, for instance, only deals with subclasses). It is possible to define custom invocation policies, that define which operations should be performed when a method is called. For instance, it is possible to log all method calls, or inspect the arguments on-the-fly for debugging purposes, or gather statistics. In this sense, PolyD offers some features typical of aspect-oriented programming. It is possible to specify exactly what should happen if null arguments are encountered (an aspect that is not normally customizable in programming languages), restrict the interpretation of the dynamic class of arguments in order to implement a more general version of "super", define custom handlers for messages that cannot be satisfied by any methods according to the dispatching policy in use. Included is also a Runabout emulation layer, that allows existing programs that use that tool to take advantage of the new features without sacrifying compatibility. There are even more features and ways to use PolyD; for a complete reference, the full manual is available below.
More information on the GNU licenses mentioned above is available on this page.
PolyD is related, to varying degrees, to a number of tools and projects. The main inspiration was certainly the Runabout, written by Christian Grothoff, from which PolyD borrows the idea of using dynamic bytecode generation to speed up dispatching. Other related tools and pages are: Visitor-related:
Multidispatching-related: Other:
|