DuckTyping in Java (and the Ubiquitous Language)

Ducks in a row...

I’ve recently discovered javaposse.com (recommended), and was listening to an podcast from last year on the DRY principle.

One of the questions asked was: when coding in Java, where do we have to repeat ourselves? There was the usual point made about generics being overly verbose (Java 7′s diamond operator will help), but another answer came back about the repetition required in having to explicitly say that a class implemented an interface in addition to just providing an implementation of all the methods in that interface… in other words, why can’t Java support duck typing:

So, suppose:

public interface IDuck {
    public void quack(int volume);
    public void float();
}

and

public class DuckLike {
    public void quack(int volume) {  .... }
    public void float() { }
}

What our speaker wanted was to be able to pass a DuckLike object around to something that would use IDucks, without having to say class DuckLike implements IDuck:

public class DuckUser {
    public void useDuck(Object o) {
        ... use the supplied object as a duck if it quacks and floats ...
    }
}

In order to support ducktyping, note that the DuckUser#useDuck takes an Object, not an IDuck.

So, one solution that came back was a utility to automatically provide a proxy for the duckLike thing that implements IDuck if it does indeed have a suitable implementation. This proxy then delegates to the underlying duckLike. I must admit this caught my fancy so I thought I’d have a go at writing it.

So, given an instance of DuckLike and the IDuck, you can write:

DuckLike duckLike = new DuckLike();
IDuck duck = DuckTyping.quacks(duckLike, IDuck.class);
if (duck != null) {
    ... use duckLike as a duck ...
}

Turns out that the utility class, DuckTyping, isn’t that difficult to write (ie it’s taking me longer to write the blog than the code did…):

package org.starobjects.misc.duck;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DuckTyping {
    @SuppressWarnings("unchecked")
    public static  T quacks(final Object duckLike, Class requiredClass) {
        final Class duckLikeClass = duckLike.getClass();
        if (requiredClass.isAssignableFrom(duckLikeClass)) {
            return (T) duckLike;
        }
        for (Method method : requiredClass.getMethods()) {
            try {
                duckLikeClass.getMethod(method.getName(), method
                        .getParameterTypes());
            } catch (NoSuchMethodException e) {
                return null;
            }
        }
        InvocationHandler handler = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                Method duckLikeMethod = duckLikeClass.getMethod(method
                        .getName(), method.getParameterTypes());
                return duckLikeMethod.invoke(duckLike, args);
            }
        };
        return (T) Proxy.newProxyInstance(
                requiredClass.getClassLoader(),
                new Class[] { requiredClass },
                handler);
    }
}

We can then updated our DuckUser library to use the new utility:

public class DuckUser {
    public void useDuck(Object o) {
        IDuck duck = DuckTyping.quacks(o, IDuck.class);
        if (duck != null) {
            ... use supplied object as a duck ...
        }
    }
}

How cool is that?

Actually, I’m not sure that it’s very cool at all.

Let’s think about the ubiquitous language of this little example. Okay, so we’ve made it possible to pass arbitrary objects to DuckUser, and if that object quacks like a duck and floats like a duck then the DuckUser will be able to use it as an (I)Duck. However, the concept of duckiness is now hidden within DuckUser. Does this represent good encapsulation? No, I think it means that in the ubiquitous langauge is missing a concept, we haven’t surfaced the concept of duckiness, and so we can’t talk about ducks.

So, hey, make the object implement the interface. We’re not violating the DRY principle when we implement an interface; we’re expressing syntactically that we intend to comply with the semantics of the concept represented by an interface (as opposed to just accidentally having some methods that are the same signature).

Interfaces are a key part of defining the ubiquitous language. Very often we start off defining the obvious, concrete classes. Only later on, with deeper understanding, do the roles that objects play to each other start to appear … it’s these roles that define the conceptual contours of the model.

So, yes, the above DuckTyping utility was fun to write (and you can pull it down from Sourceforge if you want). But I don’t think I’ll be using it in my domain models.

Advertisement

Posted on September 10, 2009, in domain driven design, random. Bookmark the permalink. 8 Comments.

  1. Actually we do use similar approach to bypass some NOv3 limits. Not elegant, but this hack works.

    • Is this also the case for NO v4? I imagine so. What are these limitations you are working around? perhaps we should address ‘em?

  2. All about NOv3 automatic mapping generation. In NOv4 this problem would be solved with stable JPA support.

    Think about class inheritance mapping ‘single table per inheritance’ strategy. Bugs occurs when you have some field that differs in classes only by type.

    [String object] at [class A extends C] and [Long object] at [class B extends C] for ex.

    When NOv3 generates single table for that inheritance it confused with equally named fields but with different types.

    Actually it leads for attempts to store string as long or long as string.

  3. public class IDuck
    shouldn’t this be an interface?

  4. Erm, I don’t see the problem with writing “implements IDuck”. Care to elaborate?

    I like the features of languages like Python where you can “mix and match” interface-esque contracts, by overriding things like iter for lists makes it one etc

    • Wikipedia has a reasonable article on ducktyping.

      But as I concluded in the blog, I’m with you; identifying the concept of a ‘duck’ helps build the ubiquitous language. Go ahead and implement IDuck. This is a *good* thing.

  1. Pingback: DuckTyping in Java (and the Ubiquitous Language) | Domain Driven … interface

Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 109 other followers