Macro that dynamically defines record based on protocol - clojure

My goal is to create a macro such that (defdummy MyProtocol MyImplementation) will create a record type as defrecord does. It would also be acceptable to just generate an implementation of MyProtocol like reify does. This record type should implement all methods of the given protocol, but just return nil for each method. e.g:
(defprotocol Annoying
(beep [x] "Make a sound"))
;; This form...
(defdummy Annoying FakeAnnoyer)
;; Should expand to this
(defrecord FakeAnnoyer []
Annoying
(beep [x] nil))
I see that when we evaluate the protocol, we have some methods that can be used to generate the implementations of the protocol methods: :sigs, :arglists, etc. However, because macros receive their arguments unevaluated, I can't access this information from inside the macro. If a macro user passes a protocol MyProtocol to my macro, I just see the symbol 'MyProtocol. It seems to me that this information is statically known at compile time, but I don't know if I can find it out when generating protocol methods.
The only way that I can think of is either to use eval or to expand to some of the inner workings of defrecord. Is there any other way?

You can use the resolve function. For instance, here is a basic implementation of your defdummy macro:
(defmacro defdummy [protocol record]
`(defrecord ~record []
~protocol
~#(for [[_ {:keys [name arglists]}] (:sigs #(resolve protocol))]
`(~name ~#arglists nil))))
Example:
(defprotocol Annoying
(beep [x] "Make a sound"))
(macroexpand-1 '(defdummy Annoying FakeAnnoyer))
;;=> (clojure.core/defrecord FakeAnnoyer [] Annoying (beep [x] nil))

Related

Group multiple namespace definitions under one namespace

Suppose I have the namespaces foo.car.components.engine, foo.car.components.transmission, foo.car.components.brakes.
In foo.car.components.engine there is (defn engine [] ...), foo.car.components.transmission there is (defn transmission [] ...),
foo.car.components.brakes there is (defn brakes [] ...).
I'd like to make these available in foo.car.components such that other namespaces only need to require foo.car.components to use engine, transmission, and brakes.
The following works, but I'm wondering if there are cleaner ways to do this or if it's even good practice.
(ns foo.car.components
(:require
[foo.car.components.engine :as engine]
[foo.car.components.transmission :as transmission]
[foo.car.components.brakes :as brakes]))
(def engine engine/engine)
(def transmission transmission/transmission)
(def brakes brakes/brakes)
I don't offhand know of a better way, but this way does come with downsides, so take these into consideration when deciding if you want to use this:
It doesn't transfer Meta information to the "wrapper", so any docstrings/other information attached to the main function won't show up in IDEs when you use the wrapper.
Along the same vein, because the wrapper doesn't have an argument list, if you ctrl+q the wrapper functions, it also won't show the available argument lists of the main function.
Having said that, Seesaw, a major Clojure library that wraps Swing does use this "technique". If I ever forget the docs/arguments of a function that has a "convenience wrapper", I just have to hit ctrl+b twice (in IntelliJ), and it will take me to the original source where I can look it over. It's ironically inconvenient, but I guess that's the price for convenience elsewhere.
To get around these faults, you could write a function (or a macro that wraps def) that transfers Meta information. Considering argument list information is stored as Meta information, that might be enough to overcome the faults.
This answer doesn't really answer your question, so I hope someone else is able to give some insight here. I thought that this was relevant information though.
You can use:
import-vars
from https://github.com/ztellman/potemkin
It doesn't seem that this feature is provided by Clojure API. You can consider https://github.com/ptaoussanis/encore look for defalias.
On the other hand, if you have brakes, transmission and engine as public interfaces and you can use them separately why would you merge them? As opposite, you can provide all definitions in components or even car which will use in turn brakes, transmission and engine. In such way, it is not necessary to expose all components.
I think the way you're doing it is the best way, because it makes explicit the sources of the defs in each namespace. If you have large namespaces with a lot of functions, you could write a basic helper function to do this for you:
(ns foo.utils)
(defn export-refs
[target-ns source-namespaces]
(doseq [ns source-namespaces
[sym f] (ns-interns ns)
:let [existing (get (ns-interns target-ns) sym)]]
(when (and existing (not= (var-get existing) f))
(throw (Exception.
(format (str "Cannot refer to symbol %s in %s from %s, because that symbol "
"already exists in the target namespace")
sym (ns-name ns) (ns-name target-ns)))))
(intern target-ns sym f)))
(ns foo.car.components.engine)
(defn engine [] (println "engine"))
(ns foo.car.components.transmission)
(defn transmission [] (println "transmission"))
(ns foo.car.components.brakes)
(defn brakes [] (println "brakes"))
(ns foo.car.components
(:require [foo.utils :refer [export-refs]]))
(export-refs 'foo.car.components '[foo.car.components.engine
foo.car.components.transmission
foo.car.components.brakes])
(ns user
(:require [foo.car.components :refer [engine transmission brakes]]))
(engine) ;; Prints "engine"
(transmission) ;; Prints "transmission"
(brakes) ;; Prints "brakes"
Whether it's "good practice" or not is up to you. Obviously it has the advantage of splitting code into smaller files with specific functionality, while allowing the import of only a single namespace. The disadvantage is that there's a bit of indirection in where the functions come from, which will make finding the function sources more difficult, and there's more risk of name collisions.

Strange unexpected defrecord behavior: a bug or a feature?

;; Once upon a time I opened a REPL and wrote a protocol
;; definition:
(defprotocol SomeProtocol
(f [this]))
;; And a record:
(defrecord SomeRecord []
SomeProtocol
(f [this]
"I don't do a whole lot."))
;; And a very useful side-effect free function!
(defn some-function []
(f (SomeRecord.)))
;; I call my function...
(some-function)
;; ...to see exactly what I expect:
;; user=> "I don't do a whole lot."
;; Unsatisfied with the result, I tweak my record a little bit:
(defrecord SomeRecord []
SomeProtocol
(f [this]
"I do a hell of a lot!"))
(some-function)
;; user=> "I don't do a whole lot."
Looks like a bug to me. I just cannot be sure after having seen so
many false compiler bug reports in c++ user group.
You need to re-define the some-function after redefining the record again. The reason for this is that defrecord creates a new type (using deftype) and using the (SomeRecord.) notation inside the function will bind the code to that type even after a new type with same name is defined. This is why it is usually prefer to use (->SomeRecord) notation to instantiate the record, using this notation will make your code work like you expected.

How do I reference a dynamically generated symbol?

I am trying to dynamically create functions based on some static public fields of a Java class. So in one file I have something like:
(intern *ns* (symbol (get-fieldname-from-class class)) some-func)
The problem is that I want to call that particular function while it isn't defined yet.
For example, the Java class has a static int PARENTHESIZED_EXPRESSION field. From this I generate a parenthesized-expression? function. This works quite nice, but when I load a Clojure file in the REPL that uses this functions I get an
unable to resolve parenthesized-expression?
error. So I have to make sure that the symbol's are interned first. How can I do this?
I realize this is not a very functional approach, but I'm a little bit hesitant to enter almost 80 similar functions for all the fields of this class. Besides, this class might be subject to change.
I wonder if you could get by using a macro like this:
user=> (defmacro f [sym] `(defn ~(symbol (str sym "?")) [x#] (= x# ~(symbol (str "java.util.Calendar/" (str sym))))))
#'user/f
user=> (f DAY_OF_MONTH)
#'user/DAY_OF_MONTH?
user=> (DAY_OF_MONTH? java.util.Calendar/DAY_OF_WEEK)
false
user=> (DAY_OF_MONTH? java.util.Calendar/DAY_OF_MONTH)
true
user=>

In clojure how can defmacro be defined in terms of itself?

I have been looking at the source for defmacro which uses "let" in its definition:
(def
^{:doc "Like defn, but the resulting function name is declared as a
macro and will be used as a macro by the compiler when it is
called."
:arglists '([name doc-string? attr-map? [params*] body]
[name doc-string? attr-map? ([params*] body)+ attr-map?])
:added "1.0"}
defmacro (fn [&form &env
name & args]
(let [prefix (loop [p (list name) args args]
However, "let" is defined as a macro itself:
(defmacro let
"binding => binding-form init-expr
Evaluates the exprs in a lexical context in which the symbols in
the binding-forms are bound to their respective init-exprs or parts
therein."
{:added "1.0", :special-form true, :forms '[(let [bindings*] exprs*)]}
[bindings & body]
(assert-args
(vector? bindings) "a vector for its binding"
(even? (count bindings)) "an even number of forms in binding vector")
`(let* ~(destructure bindings) ~#body))
Can someone explain how this works as I can't understand how "defmacro" can be defined in terms of things which need "defmacro" to already be defined. (if that makes sense :)
This is possible because before defining defmacro function in core.clj there is already a definition of let at this location (which gets redefined later). Macros are just normal functions and the var they are bound to has meta data key :macro with value true so that at compile time the compiler can differentiate between a macro (which execute at compile time) with a function, without this meta key there is no way to differentiate between a macro and a function because macro itself is a function that happens to process S-expressions.
recusrive macros work fine and occur in many place in both the clojure language core and in other programs. macros are just functions that return S-Expressions, so they can be recursive just as functions can. In the case of let in your example it's actually caling let* which is a different function (its fine to have * in a functions name), so although recursive macros are fine, this doesn't happen to be an example of them

Avoid overriding variable names

On a particular namespace I am working on I am beginning to run out of function names. Is there a way to get a warning like the one I get if I override a symbol from another namespace if I reuse a symbol which is already bound to a function in the same namespace?
If this is enough of a problem that you'd be willing to replace a (set of) core macro(s), you could try this approach:
(ns huge.core
(:refer-clojure :exclude [defn]))
(defmacro defn [name & defn-tail]
(assert (nil? (resolve name))
(str "Attempting to redefine already defined Var "
"#'" (.name *ns*) "/" name))
`(clojure.core/defn ~name ~#defn-tail))
Then any attempt to redefine an existing Var with defn will fail:
user=> (defn foo [] :foo)
#'user/foo
user=> (defn foo [] :bar)
AssertionError Assert failed: Attempting to redefine already defined Var #'user/foo
(nil? (resolve name)) user/defn (NO_SOURCE_FILE:2)
You could similarly replace defmacro; in that case you would have to call clojure.core/defmacro when defining your own variant.
Plain, unadorned def is a special form and receives magic treatment from the compiler, so you could still overwrite existing Vars with it. If you would like to guard against name clashes on that flank too, you could switch to something like defvar (used to be available in clojure.contrib.def) with a similar custom assert.
This isn't quite an answer to your question but may help avoid the issue depending on how the functions in your namespace are being used. You could make them into local functions using letfn, allowing you to reuse names for functions that are only used within the context of another function.
(defn main-fn [x]
(letfn [(secondary-fn [x] (* x x))
(another-fn [x] (secondary-fn (inc x)))]
(/ (another-fn x) 4)))
Even if you restrict yourself to single-character function names, you are in no danger of running out, as there are (about) 64 thousand Unicode characters, any one of which is a valid function name.
Given that you can in fact have names that are ten thousand characters long, you are on even safer ground.