Clojure style (and good software engineering in general) puts emphasis on lots of small functions, a subset of which are publicly visible to provide an external interface.
In Clojure there seem to be a couple of ways to do this:
(letfn [(private-a ...)
(private-b ...)]
(defn public-a ...)
(defn public-b ...))
(defn- private-a ...)
(defn- private-b ...)
(defn public-a ...)
(defn public-b ...)
The letfn form seems more verbose and perhaps less flexible, but it reduces the scope of the functions.
My guess is that letfn is intended only for use inside other forms, when little helper functions are used in only a small area. Is this the consensus? Should letfn ever be used at a top level (as I've seen recommended before)? When should it be used?
letfn is intended for use in cases of mutual recursion:
(letfn [(is-even? [n]
(if (zero? n)
true
(is-odd? (dec n))))
(is-odd? [n]
(if (zero? n)
false
(is-even? (dec n))))]
(is-even? 42))
;; => true
Don't use it at the top level.
Also don't use the defn macro anywhere else than at the top level unless you have very specific reasons. It will be expanded to the def special form which will create and intern global var.
The purpose of letfn is totally different from the purpose of defn form. Using letfn at the top level does not give you same properties of defn, since any bindings of names to functions bound inside letfn is not visible outside its scope. The binding for functions bound inside let or letfn is not available outside its lexical scope. Also, the visibility of functions bound inside letfn is independent of the order in which they are bound inside that lexical scope. That is not the case with let.
My rules are these:
If a subsidiary function is used in one public one, define it
locally with let or letfn.
If it is used in several, define it at top level with defn-.
And
Don't use let or letfn at top level.
Don't use def or defn or defn- anywhere other than top level.
Related
I'd like to hide the details of my persistence layer behind some sort of interface. In Java I would just create an interface and choose the correct implementation in some sort of bootup function. I'm still struggling on how to do that in Clojure. I don't necessarily need any type-safety here, I trust in my unit tests to find any issues there. The best thing I could come up with was to create a map containing anonymous functions with specific keys, like so:
(def crux-db {
:get-by-id (fn [id] (get-obj...))
:save (fn [id obj] (store-obj...))
})
(def fs-db {
:get-by-id (fn [id] (get-obj...))
:save (fn [id obj] (store-obj...))
})
If I'm not missing something, this would allow me to replace the database implementation by def-ing (def db crux-db) or (def db fs-db), as long as all the functions exist in all implementation maps. Somehow I feel like this is not the clojure way but I can't put my finger on it. Is there another way to do this?
Protocols are a way to do that. They let you define what functions should be there. And
you can later implement them for different things with e.g.
a defrecord.
A protocol is a named set of named methods and their signatures, defined using defprotocol:
(defprotocol AProtocol
"A doc string for AProtocol abstraction"
(bar [a b] "bar docs")
(baz [a] [a b] [a b c] "baz docs"))
No implementations are provided
Docs can be specified for the protocol and the functions
The above yields a set of polymorphic functions and a protocol object
all are namespace-qualified by the namespace enclosing the definition
The resulting functions dispatch on the type of their first argument, and thus must have at least one argument
defprotocol is dynamic, and does not require AOT compilation
defprotocol will automatically generate a corresponding interface, with the same name as the protocol, e.g. given a protocol my.ns/Protocol, an interface my.ns.Protocol. The interface will have methods corresponding to the protocol functions, and the protocol will automatically work with instances of the interface.
Since you mentioned crux in your code, you can have a peek at how they
use it
here
and then using defrecords to implement some of
them
There are several ways to achieve this. One way would be to use protocols. The other way would be to just use higher-order functions, where you would "inject" the specific function and expose it like so:
(defn get-by-id-wrapper [implementation]
(fn [id]
(implementation id)
...))
(defn cruxdb-get-by-id [id]
...)
(def get-by-id (get-by-id-wrapper cruxdb-get-by-id))
Also worth mentioning here are libraries like component or integrant which are used to manage the lifecylce of state.
When creating a new Java object via a wrapper function, what is the "constructor" naming standard? Should I prepend make- or new- to the function name? Or just call it the type of thing it returns? At one point I got accustomed to using make- because it's the way it was done in the Scheme book SICP.
For example, I'm passing some stuff to a function which eventually returns an instance of a Java class. Here are a few examples:
(def myimage1 (make-image "img.svg" 100 200)) ; These all return
(def myimage2 (new-image "img.svg" 100 200)) ; an instance of
(def myimage3 (image "img.svg" 100 200)) ; javafx.scene.image.Image
Is it the same for creating Clojure-only structs, such as maps, etc?:
(def mystruct1 (make-custom-struct args))
(def mystruct2 (new-custom-struct args))
(def mystruct3 (custom-struct args))
I prefer the last version without make- or new-, but often times the binding (for example inside a let) would have the same name, which would suggest prepending the constructor name, or using a different binding name, such as:
(let [image (make-image "img.svg" 100 200)] ...)
(let [imuj (image "img.svg" 100 200)] ...)
However other times I'd just like to use the function in-line without the cluttering of the new- or `make-':
(do-something-with-an-image (image "img.svg" 100 200))
Stuart Sierra suggests not using a prefix. His idea is that a pure function can be replaced with its implementation, and so a simple noun makes a better name in that sense than a verb.
I agree that (image ...) is the version that looks the best. However, you are right that you can easily end up shadowing the function with local variables. What can you do?
Namespaces are here to counter the issue introduced by the Lisp-1 nature of Clojure:
(let [image (png/image "file.png")] ...)
Alternatively, when you are in the same namespace, you should give better variable names: image is a little bit generic; try something more precise, like avatar or thumbnail. Note also that sometimes image is the best name to give to the variable.
You can also prefix or suffix variable names, like user-image, old-image or new-image.
Regarding functions, the make- prefix is not bad: it is readable, unambiguous and it fixes the problem of shadowing existing bindings. So don't discard it too quickly. This prefix tends to be found more often than new-, which is a little unclear: sometimes you have old and new data, where new is an adjective.
I think -> is a fun prefix, and it's already used by the factory functions generated by defrecord.
I have one function that does some (possibly lengthy) work (defn workwork [x] ...) and some other functions to check if the call will succeed ahead of time (defn workwork-precondition-1 [x] ...).
The precondition functions should be evaluated every time workwork is called (e.g. using :pre). The precondition functions should also be collected (and:ed) in a single function and made available to client code directly (e.g. to disable a button).
Which is the idiomatic way to solve this in Clojure while avoiding code duplication?
In particular, is there any way to evaluate the pre-conditions of a function without running the function body?
You can just collect your preconditions into a function:
(defn foo-pre [x]
(even? x))
Then call the function in a :pre-style precondition:
(defn foo [x]
{:pre [(foo-pre x)]}
…)
For functions introduced using defn, you can extract the :pre-style preconditions from the metadata on the Var:
(-> #'foo meta :arglists first meta)
;= {:pre [(foo-pre x)]}
And similarly for the :arglists entries for any other arities.
There are two caveats here:
The automatically-generated :arglists entry in the Var's metadata maybe be overridden. Overriding :arglists results in the above kind of useful automatically-generated metadata to be thrown out.
The {:pre [(foo-pre x)]} value returned by the above (-> #'foo meta …) expression contains foo-pre as a literal symbol – it'd be your responsibility to figure out which function it referred to at foo's point of definition. (This may or may not be possible – for example foo could be defn'd inside a top-level let or letfn form, with foo-pre a local function.)
And finally, anonymous functions may use :pre and :post, but there is currently no mechanism for extracting them from the function itself.
to evaluate the function precondition without running the function body,you can use robert-hooke library https://github.com/technomancy/robert-hooke/
(use 'robert.hooke)
(defn workwork [x] ...)
(defn workwork-precondition-1
[f x]
(if (precondition-1-satisfied? x)
(f x)
:precondition-1-not-satisfied))
(add-hook #'workwork #'workwork-precondition-1)
I spent a couple of years doing Scheme "back in the day" and am now learning Clojure. One of the "best practices" in Scheme was to define helper functions within the parent function thus limiting their visibility from "outside." Of course back then TDD wasn't done (or known!) so testing such functions wasn't an issue.
I'm still tempted to structure Clojure functions this way; i.e., using letfn to bind helper functions within the main function. Of course testing such "local" functions is problematic. I realize I can define "private" functions, but this scopes the visibility to the namespace which helps, but is not as fine grained. If you come upon a letfn within another function it's pretty clear that the function is not available for general use.
So, my question is, can one test such local functions and if so, how? If not, then is there some convention to aid in code reading so that it's clear that a function has only one caller?
TIA,
Bill
The usual approach is to just put the functions in the namespace.
One option is using metadata:
user=> (defn ^{::square #(* % %)} cube [x]
#_=> (* x ((::square (meta #'cube)) x)))
#'user/cube
user=> (meta #'cube)
{…, :user/square #<user$fn__780 user$fn__780#2e62c3f9>}
user=> (cube 3)
27
It is of course possible to write a macro to make this prettier.
defn = public
defn- = private
Perhaps I have bad Clojure coding style -- but I find that most functions I write in Clojure are small helper functions that I do not want to expose.
Is there some configuration option, where:
defn = private by default,
and to make something public, I have to do defn+?
Thanks!
No. There is not.
An alternative approach which might or might not work for you is to declare a foo.bar.internal namespace containing all the private helpers which is used by your foo.bar namespace. This has advantages over private function declarations when you want to use private functions in macro expansions.
If the "helper functions" are very likely to be used once, you could choose to make them locals of your bigger functions, or write them as anonymous functions. See letfn: http://clojuredocs.org/clojure_core/clojure.core/letfn and http://clojuredocs.org/clojure_core/clojure.core/fn.
I hardly ever use letfn myself.
The beauty of Clojure being a Lisp, is that you can build and adapt the language to suit your needs. I highly recommend you read On Lisp, by Paul Graham. He now gives his book away for free.
Regarding your suggestion of defn+ vs defn vs defn-. This sound to me like a good case for writing your own Macro. defn is a function and defn- is a macro. You can simply redefine them as you wish, or wrap them in your own.
Here follows a suggestion to implementation, based mainly on Clojure's own implementation - including a simple utility, and a test.
(defmacro defn+
"same as Clojure's defn, yielding public def"
[name & decls]
(list* `defn (with-meta name (assoc (meta name) :public true)) decls))
(defmacro defn
"same as Clojure's defn-, yielding non-public def"
[name & decls]
(list* `defn (with-meta name (assoc (meta name) :private true)) decls))
(defn mac1
"same as `macroexpand-1`"
[form]
(. clojure.lang.Compiler (macroexpand1 form)))
(let [ ex1 (mac1 '(defn f1 [] (println "Hello me.")))
ex2 (mac1 '(defn+ f2 [] (println "Hello World!"))) ]
(defn f1 [] (println "Hello me."))
(defn+ f2 [] (println "Hello World!"))
(prn ex1) (prn (meta #'f1)) (f1)
(prn ex2) (prn (meta #'f2)) (f2) )
As stated by #kotarak, there is no way (as far as I know) to do that, nor is it desirable.
Here is why I dislike defn- :
I found out that when using various Clojure libraries I sometimes need to slightly modify one function to better suit my particular needs.
It is often something quite small, and that makes sense only in my particular case. Often this is just a char or two.
But when this function reuses internal private functions, it makes it harder to modify. I have to copy-paste all those private functions.
I understand that this is a way for the programmer to say that "this might change without notice".
Regardless, I would like the opposite convention :
always use defn, which makes everything public
use defn+ (that doesn't exist yet) to specify to the programmer which functions are part of the public API that he is supposed to use. defn+ should be no different from defnotherwise.
Also please note that it is possible to access private functions anyway :
;; in namespace user
user> (defn- secret []
"TOP SECRET")
;; from another namespace
(#'user/secret) ;;=> "TOP SECRET"