See: https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure#namespaces
It bothers me that idiomatic clojure is:
(ns clojure-example
(:require [clojure.set :refer [union]]))
But idiomatic clojurescript is:
(ns clojurescript-example
(:use [clojure.set :only [union]]))
Of course, the clojurescript code would work in clojure as well, but that brings out demons who say I should use require with :refer instead!
What is the cause of this?
Actually ClojureScript does support :require :refer and has supported it for a long while (here's my commit introducing support for :refer from 12 Jun 2012). That wiki page is out of date. I have edited the section on namespaces on the wiki to bring it up to date.
As for what is idiomatic, there are of course people who dislike :use, but that hardly makes it unidiomatic after several years of production use. You're free to make up your own mind as to whether you prefer :require :refer or not.
(Although the use case where :use actually offers capabilities that :require does not -- pulling in several namespaces with (:use lib.foo lib.bar lib.quux) -- is indeed not supported in ClojureScript, by design.)
Related
I'm working through Web Development with Clojure and I noticed that the ClojureScript examples the author provides use the conventional app-name.core namespace, which is also being used by the Clojure part of the application for a lot of boilerplate code from Luminus.
ClojureScript and Clojure are often used to evaluate the same code for client and server sides of an app, respectively, so how does it differentiate between code in the ClojureScript core namespace and the Clojure core namespace? Does it use the directory structure? Can you use code from both w/o having to specify?
You program in JavaScript regardless of whether your code runs on Node.js or in a browser. Obviously depending on the platform, the API isn't the same.
My understanding is that ClojureScript is just a compiler. You write in plain Clojure (with a subset of the API) and then use ClojureScript to compile Clojure to JavaScript.
Therefore I don't think there's any difference in how namespaces are managed:
Replace . with /
Append clj or cljs
Replace - with _
Unless configured otherwise assume that src is the root directory
So app-name.core "resolves" to src/app_name/core.cljs for example.
I think (could be wrong) that on the JVM if a file doesn't exist on the disk, the compiler will look inside JARs (if any). Obviously that wouldn't happen with ClojureScript.
I have said in other answers that IMHO it is a mistake to include both frontend code (CLJS) and backend code (CLJ) in the same git repository. You fundamentally have two different programs that are running independently, are on separate hardware, and are communicating over a network. Any common utils used by both programs should be in a separate utility library, which would be a 3rd repo.
This organization provides the most independence and clarity for the 2 (or 3) codebases, independent of the language in use. It applies equally to any combination of languages used by the 2 programs:
Python & Python
Python & Java
JS (browser) & Python
CLJS (browser) & Java
CLJS (browser) & Clojure
any other combination...
So you use *.clj files for the backend code, and *.cljs files for the frontend code [1]. If you have any common utilities, make a 3rd repo and use *.cljc files for this shared library.
For frontend CLJS code, it is much easier IMHO to use the new figwheel-main and Clojure Deps tooling than the older lein tooling. Please see figwheel.org for details. This also makes it easier to keep the CLJ repl and the CLJS repl separate (no "piggieback" stuff required). It also keeps the CLJ compilation and CLJS compilation separate, which also simplifies things.
Having stated the above, I hope the answer to your original question becomes clearer. The CLJS code may have a namespace demo.core, that is compiled into JavaScript, that is running in a browser, on the user's computer. The CLJ code may also have a namespace demo.core, that is compiled into Java bytecode, that is running on a backend server in the cloud. So there is only one ns demo.core in each execution environment, so they never clash.
So, we see that the 2 compilers treat the CLJ and CLJS codebases as independent programs. This is why it is simpler IMHO to use two different git repositories to prevent conflating the two independent codebases.
Footnotes:
[1]. If you have macros in the CLJS frontend code, you will also need to define them in either *.clj or *.cljc files due to quirks in the CLJS compiler. We will ignore that complication here.
I would like to give a name to a macro and I can do it in Clojure with this method clojure.tools.macro/name-with-attributes.
What is the equivalent method in ClojureScript ?
Unfortunately you can only define macros in Clojure, not in ClojureScript. But once defined, you can use them in both.
As explained in this answer, macros are applied at compilation. And because the compiler is written in Clojure, macros must be implemented in Clojure as well.
Hope this helps.
I'm new to Clojure but my end goal in learning the language is to use the Clojurescript compiler, since I plan on using the generated code on the browser VM.
Since there tutorials are abundant for Clojure and Clojurescript is just another compiler I'm doing the Clojure tutorials, but now I got to a point where I want to know where is the line between the libraries that are core clojure that will compile to javascript fine and the ones that won't.
For example, in the tutorial I'm following for Clojure I was reading this but it seems this is already using deep Java objects, and not core Clojure commons:
user=> (.length a-string)
7
user=> (.substring a-string 3)
"name"
user=> (.substring a-string 3 5)
"na"
// And for static methods
user=> (def rt (.getRuntime Runtime))
#'user/rt
user=> (.freeMemory rt)
30462304
The beginning of the chapter said In Clojure, strings are the same as Java strings, but not that Clojure uses String from Java, which is a different thing.
So, if my goal is to develop Clojure targeting the browser, what APIs and types can I use? Is there a simple distinction for this? I imagined that anything that doesn't need to be explicitly required (core libs) would be core Clojure and I wouldn't be tying myself the Java libs.
Thank you in advance.
If you want to write code to target both Clojure on the JVM and ClojureScript, see cljx.
Without using such tools (to embed code snippets explicitly written for either backend), it is not generally expected that substantial programs will work against both independently.
I'm just trying out ClojureScript, starting out by converting something I wrote in Clojure into cljx.
When I try to compile it I get:
clojure.lang.ExceptionInfo: :refer must be followed by a sequence of symbols in :require
I'm finding some oblique references online, but nowhere where it's spelled out whether I should be able to use a :refer :all in a ClojureScript program.
If I can't do it, what's the reason for this restriction?
No, it's intentionally not possible. There was a conversation on the ClojureScript mailing list recently related to :refer :all and it looks like it will never be supported.
To quote David Nolen from that thread:
It's just bad style and as far I know the only reason it hasn't
changed in Clojure is because the core team is very adamant about
preserving backwards compatibility when possible. The conspicuous lack
of naked :use in ClojureScript was intentional.
I have started building a system with clojure, mainly because I need to use Java libraries. My main problem with Clojure is lack of proper IDE support (getting it to work well with Emacs on Windows was not trivial). I was wondering what difficulties other people have had.
Lack of "user friendly" stacktraces (coming from Haskell, it felt like a giant step back), but you get used to it eventually and learn to work your way from slime/swank.
Still having nightmare about the days when we didn't have leiningen (classpath mess, start scripts, dependency "management" hell).
It improved a lot and is improving every release it seems.
getting bitten by the "lazy bug".
(with-open [file (writer name)]
(map #(.write file (process %)) (get-data)))
and "the lazy bug" makes your file empty!
ps: the answer is dorun
An idea: if you are working in a Java environment then you might consider sticking with your Java IDE and use a Clojure plugin rather than going with Emacs etc.
For example, my setup works beautifully with:
Eclipse 3.6.1
Counterclockwise plugin for Clojure 0.2.0 RC1 (http://code.google.com/p/counterclockwise/)
Clojure 1.2 libraries (either on the eclipse build path, or automatically imported using Maven)
Interactive development using the REPL provided with Counterclockwise (nREPL)
Since I need to use a lot of Java along with my Clojure code (often in the same project!), this setup makes much more sense than wrestling with a whole new set of tools.
My problems so far:
It wasn't too easy to get EMACS/SLIME with Common Lisp AND Clojure.
Clojure 1.2.0 stacktraces are a mess so far. It's often so hard to get it what went wrong.
The debugging experience is not very nice. Tried JSWAT and Counterclockwise, but not really happy with it.
Changing my mindset from imperative to functional programming.
It got better after I read a book on lisp programming.