can cljc single-file macro definitions to work with clojurescript? - clojure

I have clojurescript successfully importing macros from other namespaces. But I wonder whether a single-file construction is/should be possible with clojure 1.7, such that a macro can be defined and used. What I have tried does not work, but maybe I've missed a detail someplace.
(ns cljc.core)
#?(:cljs
(enable-console-print!))
#?(:clj
(defmacro list-macro [x y]
`(list ~x ~y)))
(defn foo [a]
(println (list-macro a a)))
(foo :a)
This form fails with list-macro being undefined when compiling cljs; if I remove the :clj guard around list-macro, then defmacro is undefined within the cljs compilation. Is there a way?

Yes, there is a way for a single file construction.
(ns cljc.core
#?(:cljs (:require-macros [cljc.core :refer [list-macro]])))
#?(:clj
(defmacro list-macro [x y]
;; ...
Assumedly one of the next CLJS compiler versions will do the import automatically.

Related

How to use a symbol only if it is defined

I would like to execute some Clojure code that depends upon a certain var, but only if that var is defined. As a simplified example, the body of the if form should only be executed if sym is defined:
(if (resolve 'sym) (println sym))
Unfortunately, this doesn't work. If sym is not defined, the compiler still tries to resolve it and throws:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: sym in this context
From reading Rich Hickley's comment here, I gathered that this behavior is due to Clojure's use of (mostly) single-pass compilation. However, as much sense as that makes, it obviously results in undesirable behavior in this case.
I can get around the problem by forcing the symbol resolution to happen at runtime:
(if (resolve 'sym) (println (deref (resolve 'sym))))
But this is an undesirable hack. Is there a better way, or is it not possible with Clojure's read-eval model?
(Why do I need to do this? I have multiple composable profiles defined in my profiles.clj. One of them is for vinyasa, which allows me to inject various functions into the conveniently accessible . namespace. Others load various other utility libraries. In the profiles for those other utility libraries, I want to use vinyasa to inject the most important functions, but only if vinyasa is loaded. I am currently using a variation of the hack above.)
The approach recommended by #Michiel with when-let is the best way to solve this problem. Importantly, you can make the conditionality almost completely transparent by using let's ability to shadow an existing binding:
(when-let [foo (resolve 'foo)]
(foo))
;;=> nil
(defn foo []
:bar)
(foo)
;;=> :bar
(when-let [foo (resolve 'foo)]
(foo))
;;=> :bar
(defn get-when-var-defined [sym]
(when-let [var-for-sym (resolve sym)]
#var-for-sym))
(get-when-var-defined 'foo) ;;=> nil
(def foo 1)
(get-when-var-defined 'foo) ;;=> 1

Access requirements from outside of the namespace

Imagine there is the following require-statement inside a namespace:
(ns my.core
(:require '[mylib.sth :as thing]))
(def somevar 123)
Is there a way to access mylib.sth via thing also from outside this namespace? I mean to somehow get the same behavior as for the definition somevar:
(ns somethingelse)
my.core/somevar
;; =123
(my.core/thing/myf "param") ;; something like this
;; ...
resolve and ns-resolve were made for this situation.
They will return nil if the symbol is not found, otherwise they return the var, which you can deref in order to get the current bound value.
user=> (ns my.test)
nil
my.test=> (def hidden 5)
#'my.test/hidden
my.core=> (ns my.core (:require [my.test :as t]))
nil
my.core=> (in-ns 'user)
#object[clojure.lang.Namespace 0x25930632 "user"]
user=> #(resolve 'my.test/hidden)
5
user=> #(ns-resolve 'my.core 't/hidden)
5
This works, but it's also a last resort. It should be reserved for situations where you are writing code that uses namespaces and bindings that you expect to find at run time that cannot be accessible at compile time. For example I use resolve to avoid transitive AOT of my project while compiling a stub that is callable from Java; the stub -main invokes require and then resolve at runtime, using the resolved values to access the real code.
If all you are looking for is a convenience or syntactic shortcut, the better option is to explicitly require a namespace if you want to use its values.

How can I prevent symbol contamination between Clojure tests?

I use simulation-style tests in to ensure that my entire application works correctly. The core Clojure test library is used for tests, executed via Leiningen. As the -main function runs, it defines symbols for later use within its logic. The problem is that if I accidentally use a symbol created in one -main test but never defined in the current -main test, it still has a value. I would expect to get an error that the symbol is undefined, but it seems my test environment is somehow sharing state between deftest executions. How can I deal with this? Move all my convenience-driven symbol definitions to a let statement?
If you are def-ing global vars inside your function, that's generally considered bad practice and reason enough to use let as you suggest instead.
However, you can capture a snapshot the mappings of your namespace.
(def ns-snapshot (ns-map *ns*))
So that after you intern symbols
(def foo 1)
(def bar 2)
You can determine the additions
(reduce dissoc (ns-map *ns*) (keys ns-snapshot))
;=> {bar #'so.core/bar, foo #'so.core/foo}
And un-map them
(doseq [[k v] (reduce dissoc (ns-map *ns*) (keys ns-snapshot))] (ns-unmap *ns* k))
So that you'll get the desired undefined error again
foo ;=> CompilerException ... Unable to resolve symbol: foo in this context

ArityException occurs when clojure gen-class an interface with overloaded methods

I have an java interface as below:
public interface Wrapper {
void error( Exception e);
void error( String str);
}
And i am trying to create an implementation in clojure with gen-class:
(ns myimpl)
(gen-class
:name myimpl
:implements [Wrapper]
:state state
:init init
:prefix "w-"
:main false
)
(defn- w-error [this ^Exception e]
(println e))
(defn- w-error [this ^String s]
(println s))
Then i try to create an instance and call the method in repl:
> (def w (myimpl. ))
> (.error w "oops")
This will give me an ArityException: Wrong number of args (2) passed to: myimpl$w-error.
What have i done wrong here?
The following code happens to be a misconception of how Clojure functions work.
(defn- w-error [this ^Exception e]
(println e))
(defn- w-error [this ^String s]
(println s))
"Regular" functions defined with defn can't dispatch on type - only on the number of arguments.
I belive that would actually be an useful and feasible feature, but we have to settle instead for multimethods and protocol implementations which together cover the 80% case for type-dispatch needs.
I don't know why are you getting an arity exception in particular, but I'd say it doesn't matter a lot.
Lastly, you might be interested in implementing your Java interface in Java, delegating the actual functionality to Clojure code. That would require either AOT-compiling your Clojure project, or dynamically loading code via RT, Var, etc.

Clojure : loading dependencies at the REPL

I recently learned (thanks to technomancy) that, at the REPL ---
This fails:
user=> (:require [clojure.set :as set])
java.lang.ClassNotFoundException: clojure.set (NO_SOURCE_FILE:24)
Whereas this succeeds :
user=> (require '[clojure.set :as cs])
nil
at loading the clojure.set class.
Context: The former line was copied from a namespaced source file.
My primary question is : What is the change we have made, by swapping the : and ' characters, which now allows for success of the latter command ?
My 2nd question is , in general - what are the guidelines for doing things at the REPL --- as compared with doing things in normal clojure source files ? Assume here that we can load our repl from the root of a LEININGEN project, so at least the jars will be available on disk in the dependencies sub directory.
I'll go from high-level down to your particular problem:
How Clojure (or LISPs) Generally Work
REPLs, or Read-Eval-Print Loops are the core of how LISPs are designed:
The reader converts a stream of characters into data structures (called Reader Forms).
The evaluator takes collection of reader forms and evaluates them.
The printer emits the results of the evaluator.
So when you enter text into a REPL, it goes through each of these steps to process your input and return the output to your terminal.
Reader Forms
First some, clojure reader forms. This will be extremely brief, I encourage you to read or watch (part 1, part 2) about it.
A symbol in clojure is form that can represent a particular value (like a variable). Symbols themselves can be pass around as data. They are similar to pointers in c, just without the memory management stuff.
A symbol with a colon in front of it is a keyword. Keywords are like symbols with the exception that a keyword's value are always themselves - similar to strings or numbers. They're identical to Ruby's symbols (which are also prefixed with colons).
A quote in front of a form tells the evaluator to leave the data structure as-is:
user=> (list 1 2)
(1 2)
user=> '(1 2)
(1 2)
user=> (= (list 1 2) '(1 2))
true
Although quoting can apply to more than just lists, it's primarily used for lists because clojure's evaluator will normally execute lists as a function-like invocation. Using the ' is shorthand to the quote macro:
user=> (quote (1 2)) ; same as '(1 2)
(1 2)
Quoting basically specifies data structure to return and not actual code to execute. So you can quote symbols which refers to the symbol.
user=> 'foo ; not defined earlier
foo
And quoting is recursive. So all the data inside are quoted too:
user=> '(foo bar)
(foo bar)
To get the behavior of (foo bar) without quoting, you can eval it:
user=> (eval '(foo bar)) ; Remember, foo and bar weren't defined yet.
CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:1)
user=> (def foo identity)
#'user/foo
user=> (def bar 1)
#'user/bar
user=> (eval '(foo bar))
1
There's a lot more to quoting, but that's out of this scope.
Requiring
As for require statements, I'm assuming you found the former in the form of:
(ns my.namespace
(:require [clojure.set :as set]))
ns is a macro that will transform the :require expression into the latter form you described:
(require '[clojure.set :as set])
Along with some namespacing work. The basics are described when asking for the docs of ns in the REPL.
user=> (doc ns)
-------------------------
clojure.core/ns
([name docstring? attr-map? references*])
Macro
Sets *ns* to the namespace named by name (unevaluated), creating it
if needed. references can be zero or more of: (:refer-clojure ...)
(:require ...) (:use ...) (:import ...) (:load ...) (:gen-class)
with the syntax of refer-clojure/require/use/import/load/gen-class
respectively, except the arguments are unevaluated and need not be
quoted. (:gen-class ...), when supplied, defaults to :name
corresponding to the ns name, :main true, :impl-ns same as ns, and
:init-impl-ns true. All options of gen-class are
supported. The :gen-class directive is ignored when not
compiling. If :gen-class is not supplied, when compiled only an
nsname__init.class will be generated. If :refer-clojure is not used, a
default (refer 'clojure) is used. Use of ns is preferred to
individual calls to in-ns/require/use/import:
REPL usage
In general, don't use ns in the REPL, and just use the require and use functions. But in files, use the ns macro to do those stuff.
The difference is that require is a function used for importing code, whereas :require is a keyword.
Remember what happens when you use a keyword as a function:
=> (type :require)
clojure.lang.Keyword
=> (:require {:abc 1 :require 14})
14
it looks itself up in the map. So when you pass [clojure.set :as set] to a keyword, it's trying to evaluate that to a vector, and fails because it doesn't know what clojure.set is. The Clojure docs say:
Keywords implement IFn for invoke() of one argument (a map) with an
optional second argument (a default value). For example (:mykey
my-hash-map :none) means the same as (get my-hash-map :mykey :none).
You may have been confused by the ns macro:
(ns foo.bar
(:refer-clojure :exclude [ancestors printf])
(:require (clojure.contrib sql sql.tests)) ;; here's :require!
(:use (my.lib this that))
(:import (java.util Date Timer Random)
(java.sql Connection Statement)))
ns macro:
When you type:
(ns some-great-ns
:require my-form)
you use the :require reference in which you state what would you like to use from the given namespace. It is equivalent to writing:
(in-ns 'some-great-ns)
(require 'my-form)
Notice that in the ns form (unlike the in-ns function call), you don’t have to quote your symbol with '. You never have to quote symbols within ns.
require function
As stated, can run: (require 'some-great-ns) in some given namespace so you could use it. To use it, you'll have to use full qualified name, unless you also use: refer function: (refer 'some-great-ns) right after you required the namespace.
You can do those both functions in one: (use 'some-great-ns). Now you don't need to write: (some-great-ns/my-form). Simply: my-form.
And of course you can also use the :as, :exclude, :only and :rename keywords in both the macro reference and in the function.
Differences between the macro and the function:
As stated above, usage of symbols in function, no need in the macro
You can require multiple libraries in a (:require) reference as follows:
(ns my-great-namespace.core
(:require [some-other-ns.a.b :as ab]
[some-other-other-ns.c.d :as cd]))
Where in function writing you should write 2 lines:
(in-ns my-great-namespace.core)
(require 'some-other-ns.a.b :as 'ab)
(require 'some-other-other=ns.c.d :as 'cd)
The require reference also allows you to refer names, for example:
(ns my-great-namespace.core
(:require [some-other-ns.a.b :refer [some-func]]))
Where in function you should do:
(in-ns my-great-namespace.core)
(require 'some-other-ns.a.b)
(refer 'some-other-ns.a.b :only ['some-func])