Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

There are Clojure dialects (Clojure, ClojureScript, ClojureCLR) hostd hosted on several different platforms. We wish to write libraries that can share as much portable code as possible while leaving flexibility to provide platform-specific bits as needed, then have this code run on all of them.

...

The #js tagged literal is not known on the Clojure platform, but the reader should read and skip it without failure.

Potential issueCLR extended symbol problem: Clojure CLR needed to expand the valid uses an expanded set of valid symbols and uses in the reader. The #| reader extension from Common Lisp to support this in the CLRwas implement in ClojureCLR to delimit symbols containing otherwise invalid characters. The corresponding symbols are not currently readable by Clojure or ClojureScript.  The #| extension support is described here: https://github.com/clojure/clojure-clr/wiki/Specifying-types. The #| reader extension may would need to be supported in Clojure and ClojureScript readers to support the full set of valid ClojureCLR symbols in feature expressions.

...

  • Clojure will continue to read only .clj files. The file will be read by the Clojure reader and feature expressions will be applied.
  • ClojureScript will first look for .cljs files, then for .clj files. The .clj file will be read by the ClojureScript reader and feature expressions will be applied.
  • ClojureCLR - ???
Potential ClojureScript issue: existing projects may have macro .clj files in the same namespace where a file with shared code should go. In this case, the project will need to be refactored, likely with the macros in a different location.
CLJS source extension problem: ClojureScript currently expects source files to end (only) in .cljs. There are a number of places in the code where this assumption is made:
  • clj.cljs.compiler/rename-to-js - renames .cljs file name to .js file name. 
    • regex is easily fixed for this to cover both .clj and .cljs
  • clj.cljs.compiler/cljs-files-in - given a directory, finds all .cljs files to compile
    • used by clj.cljs.repl/analyze-source, which is used by clj.cljs.repl.browser/-setup and clj.cljs.repl/repl
    • can grab .clj too, but may include macro files not previously included - how do we distinguish here?? see next question.
  • clj.cljs.analyzer/ns->relpath - given a namespace, find the resource path
    • can check first for .cljs path, then .clj path (adds resource check where prior was simple string manipulation)
  • clj.cljs.closure/cljs-source-for-namespace - given a ns, find path and url of ns

    • can check first for .cljs resource, then .clj resource
  • clj.cljs.repl.rhino/goog-require - given ns, makes cljs resource path

    • can check first for .cljs resource, then .clj resource
  • clj.cljs.repl.browser/send-static - serves static resources

    • add support for serving .clj as well as .cljs
 
CLJS accidental macro compilation problem: when we collect all the ClojureScript code to compile, we will (accidentally) include .clj macro files that should only be read for macro expansion.

We use a single classpath (often merged from several directories within a library) to load several kinds of ClojureScript resources:
  • ClojureScript-only files: .cljs - compiled as CLJS
  • Mixed source files: .clj (presumably with feature expressions) - compiled as CLJS (NEW)
  • ClojureScript macro files: .clj (loaded as needed for macro support in CLJS)
Because mixed and macro files have the same extension, we need a way to indicate that macro files should not be compiled as ClojureScript. Possible solutions:
  1. Modify the way ClojureScript loads code to specify separate paths for ClojureScript code and macro code  NO
    1. Likely breaks many existing projects which mingle these into the same source path.
    2. Also breaks library publishing as a single jar.
  2. Add build option to specify names to skip during compilation (the macro namespaces).   NO
    1. require-macros would ignore this directive so require-macros would still load the ns'es
    2. Existing CLJS projects would still work if the code in the macro files happened to be compile-able by ClojureScript
    3. This capability would also make it easier to mingle Clojure and ClojureScript projects in the same project in a single source tree (with capability to ignore certain files for CLJS for reasons other than avoiding compilation of macro files)
    4. Main problem is that if published as a library, there is no way to get this ns exclusion list to users of the published library. Would have to also invent some way to specify that list of namespaces in jar metadata etc.
  3. Add marker in macro namespaces to identify them as being skipped for compilation  INVESTIGATING
    1. Add namespace meta or other indicator that this .clj file is only included for macros not for compilation - use existing parse-ns for this
    2. Could automatically be picked up by downstream users of code published as a library

Open Extension

One consequence of feature expressions is that a library must encode solutions for all of the supported platforms in the source code at packaging time (in other words, extension is closed to external users).

...

Example:

No Format
Library files:
 src/my/core.clj - ns requires my.thing
 src/my/thing.clj - Clojure implementation of my.thing (loaded by Clojure)
 src/my/thing.cljs - ClojureScript implementation of my.thing (loaded by ClojureScript)
Open ClojureScript question:is it possible to have a single .clj namespace that is used for both feature expressions when loaded in a Clojure context and macros when loaded via require-macros?

Open ClojureScript question: Is it possible to AOT and publish a library with Clojure .class files that will be loaded when the library is used by Clojure and .cljs files with the same namespace that will be loaded and used by ClojureScript? ClojureScript Tooling Support

ClojureScript tooling needs to be aware of the change in supported file extension names and possibly new build options. Need to ensure tools are able to support the new mixed-language projects well:

  • lein-cljsbuild - most ClojureScript projects today are built with the lein-cljsbuild plugin. 
    • compiler.clj - needs to properly account for ClojureScript .clj files
    • features - might need to add support for specifying non-default feature set when testing
  • austin?
  • what else?

 

FAQ

  1. What about non-boolean expressions for things like Clojure version, JDK version, etc?  Out of scope. The "compile-if" trick covers many of those (relatively rare) cases already.

Patches

JIRA Tickets and patches:

...