1

I am trying to wrap an implementation and dynamically generate the reify clause for all the interfaces the wrapped object implements.

For example:

I want to generate:

(reify
  BaseInterface
    (fee [_] (custom-operation wrapped))
    (foo [_] (.foo wrapped)))

or

(reify
  BaseInterface
    (fee [_] (custom-operation wrapped))
    (foo [_] (.foo wrapped))
  AnotherInterface
    (bar [_] (.bar wrapped)))

depending on whether wrapped implements only BaseInterface or both BaseInterface and AnotherInterface.

I tried something like the following, but it fails as the macro is evaluated at compile time and my second argument (the cond-> expression) doesn't have its runtime value:

(defmacro add-interface-implementations
  "Adds additional interface implementations to a reify expression.
   This is useful to create a reify expression dynamically without introducing if-else branching."
  [reify-expr interface->methods]
  (reduce
    (fn [expr# entry#]
      (println "expr#" expr#)
      (println "entry#" entry#)
      (let [[interface# body#] entry#]
        (cons
          (first expr#)
          (cons interface#
                (reduce
                  (fn [e# m#]
                    (cons m# e#))
                  (rest expr#)
                  body#)))))
    reify-expr
    interface->methods))

(add-interface-implementations
  (reify
    BaseInterface
      (fee [_] (custom-operation wrapped))
      (foo [_] (.foo wrapped)))
  (cond-> {}
    (instance? AnotherInterface foo)
    (assoc AnotherInterface [(bar [_] (.bar wrapped))])))

Any suggestions on how to achieve what I'm trying. I want avoid the if-else branching as it leads to combinatorial explosion as soon as I have more interfaces.

shams
  • 3,460
  • 24
  • 24
  • You could pass in a list of possible interfaces, then use `(isa? child parent)` in a loop to keep only the desired ones. Then, construct the `reify` command. However, since you don't have `wrapped` or construct the `reify` command until runtime, I think you'll have to use `eval`. Probably a bad sign. Why do you wish to do this? – Alan Thompson Jun 11 '19 at 00:44
  • I'm creating a wrapper for an object to override certain methods. To preserve the same behavior I need to implement all the interfaces the wrapped object implements. – shams Jun 11 '19 at 00:58
  • But it seems you would have to know in advance which methods you're overridding, right? The use-case may be clearer with a more realistic example target instead of `wrapped`. – Alan Thompson Jun 11 '19 at 15:57
  • I updated the example with a `fee` method that is overridden. The other methods just need to be delegated to based on whatever interface `wrapped` implements. – shams Jun 12 '19 at 00:43

0 Answers0