Can we use macros to statically dispatch on a return type in Clojure?

151 Views Asked by At

Now we know that dispatch on Clojure Protocols, strictly speaking, is dynamic.

We see here a fantastic example of compile-time dispatch using a macro:

(defmacro case+
  "Same as case, but evaluates dispatch values, needed for referring to
   class and def'ed constants as well as java.util.Enum instances."
  [value & clauses]
  (let [clauses (partition 2 2 nil clauses)
        default (when (-> clauses last count (== 1))
                  (last clauses))
        clauses (if default (drop-last clauses) clauses)
        eval-dispatch (fn [d]
                        (if (list? d)
                          (map eval d)
                          (eval d)))]
    `(case ~value
       ~@(concat (->> clauses
                   (map #(-> % first eval-dispatch (list (second %))))
                   (mapcat identity))
           default))))

Here the writer argues that you will never be able to dispatch on return type in Clojure. To me it seems that with a sufficiently powerful macro, you can do anything.

My question is: Can we use macros to statically dispatch on a return type in Clojure?

1

There are 1 best solutions below

0
On BEST ANSWER

Theoretically, you can use macros to build a Clojure DSL with Haskell's type semantics, so yes strictly speaking it's possible.

However, from a practical standpoint, dispatching on return type at compile-type means making this information available and propagating it at compile-time. There's no built-in 'return type' in Clojure (all functions accept a variable number of Object-typed arguments and return an Object), so you'd probably have to roll out your own type system and require large parts of your programs to participate in it (à la Type Clojure), with the constraint that the type analysis must be available as soon as you use your macro.

The case of case+(pun intended) is different because it it doesn't require a type system, it's mostly a matter of evaluation order.