Duck typing in Java

August 20th, 2007 | 9 Comments »

While the Wikipedia entry on duck typing is quite thorough, Dave Thomas has a much more succinct and simpler definition:

In Ruby, types are defined as the capabilities of objects.

And that is a very interesting definition. Unlike with strong statically-typed languages (such as Java), Ruby doesn’t care about the actual type of the object being passed to a method, as long as it has all the methods that are used in that specific context. Leaving the relative merits and shortcomings of this approach aside for another entry, is this something that can be used in Java? Or, more interestingly, is it something that is used in Java? The answer is quite simple – yes. And not in third-party code; in the JDK itself.

The first example will be the Serializable interface. This is an odd duck (quack quack :). On one hand, it is a marker interface since it has no methods. On the other hand, classes that require special handling during the serialization / deserialization must define implement special methods with these exact signatures:

private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException;
private void writeObject(java.io.ObjectOutputStream stream) throws IOException;
private void readObjectNoData() throws ObjectStreamException;

At runtime, the ObjectStreamClass uses reflection to query the actual object to see if it has these methods. If it does, they are used (once again, using reflection) instead of the default (field by field) behavior. The reason behind having the Serializable interface empty and the method signatures “magic” is, quite frankly, not apparent (you’re welcome to shed more light in the comments). What would happen if these were defined publicly in Serializable (and had empty implementation in a hypothetical SerializableAdapter)? It’s not that suddenly anybody would gain access to the internals of the specific object. Calling writeObject directly is the same as creating an OutputObjectStream and calling writeObject on it. Not only that, even with the current “duck” implementation you can use reflection to query these methods, set them to accessible and call them. A minor annoyance in having all these methods in the Serializable interface would be that you would have to implement all of them if you already extend some other class.

The second example is the UIManager.getUI method. This is where it gets even more complicated than the serialization. To create a UI delegate for a specific component, the implementation first looks up the classname of the UI delegate in the table set up by the current look-and-feel. Then, it uses reflection to call the “magic” static createUI method that must have a single JComponent parameter. This method is then called to create an actual UI delegate. Interestingly enough, this elaborated lookup is not really necessary. The code can be made compile-type safe by using a simple factory that returns UI delegates based on the passed component; just as the look-and-feel fills the lookup table (UIDefaults), it can use the same “switching” to create the UI delegates. The issue with handling third-party component suites such as SwingX or JIDE can be easily addressed by providing an API on the look and feel class that allows installing lookup extensions. This example is a little further from the “pure” duck typing in that it returns a ComponentUI object. This is, of course, not strictly necessary since the relevant code can use reflection to call the methods declared and implemented in this class (which could be quite tiresome, but certainly doable).

There are a few other places throughout the JDK code that use reflection – notably for beans, JMX, a few XML parsers and even the Class class itself (in the getEnumConstants) method. And so, the next time you hear somebody mentioning duck typing, know that this technique is not restricted to dynamically typed languages.


9 Comments on “Duck typing in Java”

  1. 1 brantb said at 5:38 am on August 21st, 2007:

    “The reason behind having the Serializable interface empty and the method signatures “magic” is, quite frankly, not apparent (you’re welcome to shed more light in the comments).”

    Notice the methods that are required are private. I believe the designers did this so these methods were only available to the serialization “engine” and not available to be called by an random code. If the methods were added to the interface, then they would have to be public.

  2. 2 Kirill Grouchnikov said at 8:13 am on August 21st, 2007:

    Brant, these methods are as good as public. The signatures can’t change since that would break all the custom serialization code, and calling writeObject on an ObjectOutputStream passing this object is as good as calling writeObject on the object itself. Not to mention that you can copy the implementation that uses reflection to call this method. So what’s the point?

  3. 3 Laird Nelson said at 10:10 am on August 21st, 2007:

    If the methods are private, and can nevertheless be accessed by the serialization machinery, all of which is true, then you don’t need to call super.read/writeObject, and you are guaranteed by specification and contract that each class’ declared read/writeObject will be called by the serialization machinery. Otherwise it seems to me that if I subclass your class, and decide to bypass its serialization mechanism midstream, I could do so by simply refusing to call super.read/writeObject. There are probably security holes in there somewhere.

  4. 4 Kirill Grouchnikov said at 10:17 am on August 21st, 2007:

    Laird,

    That is an interesting point. The current implementation indeed takes care of serializing / deserializing the fields from the super class (if it implements Serializable interface), and it is a very good thing (since you can easily forget to call the super implementation in the hypothetical situation where the interface explicitly declares all these methods). However, i can’t readily see what security holes does it open. At most you end up with incompletely initialized object after reading it from the stream.

  5. 5 Tommy Morgan said at 10:22 am on August 21st, 2007:

    The reason the interface is empty is because those methods are not always required; it is only in the event of ‘special handling’ (not that I’m sure why you’d need it, but it’s there anyway).
    A better question would be why these methods aren’t just present as part of Object, in order to avoid this whole retrospection silliness.

  6. 6 Tommy Morgan said at 10:25 am on August 21st, 2007:

    The reason the interface is empty is because those methods are not always required; it is only in the event of ‘special handling’ (not that I’m sure why you’d need it, but it’s there anyway).
    A better question would be why these methods aren’t just present as part of Object, in order to avoid this whole retrospection silliness.
    In fact, it seems a bit strange to me that you would even consider retrospection when you have the capability to use an interface/inheritance and avoid mucking around with code that’s not only less intelligible, but slower to boot.

  7. 7 Ricky Clarkson said at 10:28 am on August 21st, 2007:

    Dave Thomas’ definition doesn’t actually require dynamic typing, hence you could do it in a statically typed language without reflection, as I demonstrated in my blog some time ago – http://rickyclarkson.blogspot.com/2006/07/duck-typing-in-java-and-no-reflection.html

    However, without tool support I found that technique impractical. If Java had type inference I think it could work – I can certainly imagine a statically typed language that supported duck typing. Arguing with myself here – this misses a point – it might not be possible to tell statically whether a given behaviour is supported by a certain object. If you’re writing code where that is the case, I don’t see why you would want to use a statically typed language.

    By the way, using the term “strongly-typed” usually means “better-typed”, it just means that the author considers a certain typing system better than another. Ruby is strongly-typed – the term you wanted to describe Java with is “statically-typed”.

  8. 8 Kirill Grouchnikov said at 9:37 am on August 22nd, 2007:

    Ricky,

    As many of your commenters pointed out, your approach is not duck typing as defined by the person who coined this term. Unless a class implements the specific interface, it can not be passed to a method that expect an instance of that interface, even if the class has all the methods from the interface. So, no, it’s not close to duck typing.

  9. 9 Ricky Clarkson said at 12:53 pm on August 22nd, 2007:

    Kirill,

    Of course you’re right, unless you equate a method with an interface. That’s what I was doing – as soon as you have one method per interface you may as well treat an interface as a method declaration. In a language designed for this (or one that gets out of your way and lets you fiddle) you could make it so that whenever you declare a method in an interface, another interface is generated containing that method, and the interface you’re writing gets to extend the generated one.

    What I did in Java is an emulation of that, so if you look at it from the wrong angle, you won’t see that it’s duck typing, because there’s too much stuff in the way, just as many Java programmers would fail to recognise GTK code in C as being OO.

    If I had an automatic translation mechanism that let me write as you do normally, but generate the types without making you see the verbose version, you would probably then agree that it was more like duck typing.