In Clojurescript how can I use multiple symbols or macros? - clojure

To "use" symbols in Clojurescript I often find myself having huge headers in clojurescript files, something like this:
(:use-macros
[webapp.framework.client.coreclient :only [defn-ui-component ns-coils write-ui read-ui]])
(:use
[webapp.framework.client.coreclient :only [log amend-record component-fn write-ui-fn]]))
:but I would like to have something more compact like in Clojure, so that I can just have:
(:use-macros [webapp.framework.client.coreclient])
(:use [webapp.framework.client.coreclient]))
How can I do this?

It is not supported and it seems that it won't be supported. "use" is considered a bad practice both in Clojure and ClojureScript as it makes the code less readable.

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.

clojure/script expanding a macro into multiple 'def's inside a 'do' block

Not sure if valid question, but i'm learning macros and i'm trying to write a macro (for clojurescript but should be same thing) so i can do nicer js/require in node.
The syntax will look like this:
(import ["some-module" :as module1]
["some-other-module" :as module2])
and it would expand to this:
(do
(def module1 (js/require "some-module")
(def module2 (js/require "some-module"))
My question is:
Is it ok to do 'def' inside a do block?
cljs does not seem to complain, but is it ok from a macro design stand point?
Yes, using the (do (def ...) (def ...)) pattern is generally the only way to def multiple things in a macroexpansion.

Why should you prefer :require :refer :all over :use in clojure

In his Clojure Style Guide the author writes the following,
Prefer using :require :refer :all over :use in ns macro
He does not give any explanation why this is a good idea. Is there
a good reason to avoid the use of :use in the ns macro?
I'd suggest you take a look at the original discussion, which lead to this rule. The core rationale can be found here. I'll include here the start of the discussion:
There's been discussion previously about the complexity of the ns
macro. In particular the fact that :use causes all vars to be referred
by default is widely seen as unfortunate, and the distinction between
use and require is a source of conceptual overhead for people new to
the language. We can't change the fact that :use refers everything by
default without breaking lots of existing code. But it would be
possible to enhance :require to support referring specified vars,
leaving us free to deprecate or otherwise discourage the use of :use.
Rather than this form:
(ns mork.test
(:use [mork.stats :only [summarize-group]]
[mork.utils :only [strip resolve-fn]]
[clojure.test])
(:require [mork.view :as view]
[clojure.java.io :as io]
[cheshire.core :as json])
(:import (java.io PushbackReader))
We could use this:
(ns mork.test
(:require [mork.stats :refer [summarize-group]]
[mork.utils :refer [strip resolve-fn]]
[clojure.test :refer :all]
[mork.view :as view]
[clojure.java.io :as io]
[cheshire.core :as json])
(:import (java.io PushbackReader))
It has been agreed upon in previous threads that keeping :import as a
distinct concept from :require is desirable, and I agree that we
shouldn't conflate between Clojure vars and Java classes.
There are rare cases when referring all the vars in a namespace is
acceptable, (in particular when writing test namespaces it seems
reasonable to bring in all of clojure.test and the namespace under
test) so we should probably support :refer :all for such a case, as
long as it's not the default.
My impression is that there are two reasons. 1) In doing so, you are more likely to avoid any name clashes and/or accidental overshadowing. 2) Such practices give greater transparency about the ultimate source of the functions and variables used in the code. The first one is pretty practical, and Chiron's answer provides a great demonstration.
The second one is more subtle, but if you are using a lot of libraries, it can be pretty important. Let's say you do:
(ns your-namespace
(:use [library-one]
[library-two]
[library-three]
[library-four]
[library-five]))
And then somewhere, later in your code, you invoke:
(important-function some-arg some-other-arg)
If important-function is defined in, for example, library-three, then you (or whoever is trying to make sense of your code) have to go digging through each of those libraries' code to figure out what it does--because there's nothing to indicate which library is its source! Well, actually, if you have a REPL available, you should be able to figure it out by doing:
your-namespace> `important-function
> library-three/important-function
But that kind of hidden information is probably not the best thing to inflict on other people (including your future self) who may wish to understand your code. On the other hand, :required libraries always come with a prefix. So instead, your code would look like:
(ns your-namespace
(:require [library-one]
[library-two]
[library-three]
[library-four]
[library-five]))
...
(library-three/important-function some arg some-other-arg)
Which makes it very clear where important-function is defined. Note that this should be equivalent to specifying :refer :all. Although :refer :all could indicate to others that you considered specifically which vars to reference, and made a conscious decision to include all of them from that library.
If you are not worried about name clashing...well you probably should be. But if you still aren't, and you want to be clear about vars' sources, then you could always do :use with :only. For example:
(ns your-namespace
(:use [library-one :only []]
[library-two :only []]
[library-three :only [important-function]]
[library-four :only []]
[library-five :only []]))
...
(important-function some arg some-other-arg)
Obviously, if you are :useing libraries with blank :only vectors, than you might as well not :use them in the first place, I just wanted to unify with the previous examples. And doing :require may seem verbose, but you can always shorten it by aliasing with :as. Fragment example:
(ns your-namespace
(:require [library-three :as L3]))
(L3/important-function some-arg some-other-arg)
See also, this SO question, and this guide about libraries and namespaces in Clojure.
Separation of concerns. require let you load namespaces, refer let you define how you refer to vars within those namespaces. use complects the two concerns.
With :require you have only one place where you are defining your namespace imports and you can easily switch from referring all functions to referring a few functions or just requiring the namespace (or mix and match however you like).
(:require [foo.bar]
[foo.baz :refer :all :as baz]
[foo.foobar :as fb :refer [bazbaz]])
Because with :require you will have a clear indication which namespace owns a function.
(:require [clojure.json :as json])
(:require [clojure.xml :as xml])
(json/read "file")
(xml/read "file")
In case of :use
(read "file")
How you are going to know which namespaces owns read function? If I'm maintaining your code, I have to check ns macro and start searching for read function in each use qualified namespace.

What does the idiomatic (defn -main ...) mean in a clojure program?

I'm familiar with packages from e.g. Java and Lisp, but what I'm seeing in other people's code is some apparent idioms like calling the entry point '-main' and using a backtick for the namespace name in (in-ns `foo), that kind of thing. I don't see these spelled out anywhere in docs or tutorials. Is there some resource which explains such conventions around structuring programs?
Edit:
I think I must have picked up the backtick thing from this answer: Splitting a Clojure namespace over multiple files, which I stumbled across while trying to make sense of (defn -main ...). Given the author, I took it as best practice. However, now that I poke around in the Clojure sources he cites, I see that only the regular quote is used. I guess most likely it's a typo.
(Narrowed the scope of the question title accordingly)
The default for gen-class is to use - as the prefix for method names of that class. Which is why -main is the default entry point for java -cp clojure.jar yourclass
Backticks qualify their argument with the current namespace, so (in-ns `foo) is the same as (in-ns 'current-namespace/foo) and I don't think that's particularly idiomatic. The idiomatic way is to put each namespace in its own file with (ns ...) at the top, and use or require them as needed.

Get available clojure namespaces

Is there an idiomatic way to get available namespaces that can be used?
(all-ns) returns only already used namespaces. (Package/getPackages) returns all Java packages available for import, but only those Clojure namespaces that are already used.
Then I stumbled upon this post, but it uses some classpath magic.
So I want to get something like ('clojure.core 'clojure.set ... 'clojure.contrib.accumulators 'clojure.contrib.condition ...) if I have the clojure.jar and contrib.jar on my classpath, but I haven't used anything yet.
You will need to do "classpath magic". Since there is no kind of registry, you have to walk the classpath and look in every clojure source file to determine what namespaces are available. (In case the files are not AOT compiled. Otherwise you'll need a different heuristic.)
I think the function used in the linked post is the best way to go: clojure.contrib.find-namespaces/find-namespaces-on-classpath.
Deprecated since Clojure 1.3.0; use now clojure.tools.namespace.find/find-namespaces and clojure.java.classpath/classpath from http://github.com/clojure/java.classpath
I have found bultitude to be a great tool for doing this.
Example:
user=> (require '[bultitude.core :as b])
nil
user=> (take 10 (b/namespaces-on-classpath))
(bultitude.core-test bultitude.core clojure.data clojure.string clojure.test clojure.xml clojure.inspector clojure.repl clojure.set clojure.test.junit)
user=> (b/namespaces-on-classpath :prefix "bultitude")
(bultitude.core-test bultitude.core)