Search code examples
clojuremultimethod

Clojure Multimethod dispatch on Java interface


Say I have a Java method that returns an object of some parent interface. The classes of the objects returned by this function are undocumented, however there is a rich and well documented hierarchy of interfaces all extending the parent interface. So for example:

public class Person {
   public IMeal favoriteMeal() { ... }
}

public interface IBreakfast extends IMeal { ... }
public interface ILunch extends IMeal { ... }
public interface IBrunch extends IBreakfast, ILunch { ... }

If I knew (and was confident in the stability of) the underlying objects, I could write a multimethod to dispatch on the various objects returned by that method:

(defmulti place-setting class)
(defmethod place-setting Omelet [meal] ...)

However, since only the interfaces are public, I'd rather dispatch on those. Is there a (good) way to dispatch on interfaces? Perhaps like:

(defmulti place-setting magic-interface-dispatch-fn)
(defmethod place-setting IBreakfast [meal] ...)

Solution

  • This already works perfectly fine:

    Note:

     public interface IFn extends Callable, Runnable
     public class Keyword implements IFn
    

    And then:

    (defmulti print-stuff class)
    (defmethod print-stuff Callable [x] {:callable x})
    (defmethod print-stuff :default [x] :not-found)
    (print-stuff :foo) ;; => :callable
    

    Note, multimethods always uses isa? internally on the (potentially custom) hierarchy. And (isa? Keyword Callable) is true.