Clojure Interview Questions
1.When Should I Use Multimethods?
Answer:Multimethods are extremely flexible, and with that flexibility comes choices. How should you choose when to use multimethods, as opposed to some other technique? I approached this question from two directions,asking the following:
• Where do Clojure projects use multimethods?
• Where do Clojure projects eschew multimethods?
Let’s begin with the first question, by reviewing multimethod use. The multimethod use in several open source Clojure projects is summarized in Figure 8.1, on the following page.
Project LoC Dispatch Dispatch Total
By Class By Ad HocType
Clojure 5056 4 3 7
Clojure-contrib 3585 2 1 3
Compojure 1255 0 0 0
Webjure 850 0 0 0
Figure 8.1: Multimethod use in Clojure projects
The most striking thing is that multimethods are rare—about one per 1,000 lines of code in the projects sampled. So, don’t worry that you are missing something important if you build a Clojure application with
few, or no, multimethods. A Clojure program that defines no multimethods is not nearly as odd as an object-oriented program with no polymorphism.Many multimethods dispatch on class. Dispatch-by-class is the easiest kind of dispatch to understand and implement. We already covered it in detail with the my-print example, so I will say no more about it here. Clojure multimethods that dispatch on something other than class are so rare that we can discuss them individually. In the projects listed in the table, only the Clojure inspector and the clojure-contrib test-is libraries use unusual dispatch functions.
Answer:To define a multimethod, use defmulti:
(defmulti name dispatch-fn)
name is the name of the new multimethod, and Clojure will invoke dispatch-fn against the method arguments to select one particular method (implementation) of the multimethod.Consider my-print from the previous section. It takes a single argument,the thing to be printed, and you want to select a specific implementation
based on the type of that argument. So, dispatch-fn needs to be a function of one argument that returns the type of that argument. Clojure has a built-in function matching this description, namely, class.
Use class to create a multimethod called my-print: Download examples/multimethods.clj
(defmulti my-print class)At this point, you have provided a description of how the multimethod will select a specific method but no actual specific methods. Unsurprisingly,attempts to call my-print will fail:
(my-println "foo")) java.lang.IllegalArgumentException: \No method for dispatch value.To add a specific method implementation to my-println, use defmethod:(defmethod name dispatch-val & fn-tail)name is the name of the multimethod to which an implementation belongs. Clojure matches the result of defmulti’s dispatch function with dispatch-val to select a method, and fn-tail contains arguments and body forms just like a normal function.Create a my-print implementation that matches on strings:Download examples/multimethods.clj (defmethod my-print String [s](.write *out* s))Now, call my-println with a string argument:(my-println "stu")| stu) nil
3.When to Use Macros?
Answer:Macro Club has two rules, plus one exception.The first rule of Macro Club is Don’t Write Macros. Macros are complex,and they require you to think carefully about the interplay of macro expansion time and compile time. If you can write it as a function,think twice before using a macro.The second rule of Macro Club is Write Macros If That Is The Only Way to Encapsulate a Pattern. All programming languages provide some way to encapsulate patterns, but without macros these mechanisms are incomplete. In most languages, you sense that incompleteness whenever you say “My life would be easier if only my language had feature
X.” In Clojure, you just implement feature X using a macro.