Skip to end of metadata
Go to start of metadata

The Problem

To proceed to decoupling the clojurescript compiler from its JS backend, we need to have no JS-specific content inside the parse/analyze phases of the compiler.

For the moment, the macro-expansion phase is highly dependent on macros that are js specific. Those macros are defined in the cljs.core namespace (clojure side)

A solution to this problem is to make the namespace in which those macros are defined parametric, and to put the code for each backend in its own namespace (cljs.js.core for js, for example)

The big question is wether the cljs.core namespace on the clojurescript side also needs to be moved in the same namespace (cljs.js.core), or wether it should stay in the cljs.core namespace

It could stay in cljs.core because, at runtime, there is only gonna be one cljs.core. But should it ?

Option 1 : Move everything to a backend specific namespace (namely cljs.js.core)

In this scenario, the current clojure cljs.core, and clojurescript cljs.core would both be renamed to cljs.js.core. Every reference to cljs.core in the compiler would be changed to reference a bound variable containing the name of the core namespace.

Pros

  • Easier to get right
  • Coherency - cljs.core clojure-side and clojurescript side are two parts of the same standard library

Cons

  • We expose on the runtime side that the compiler has several backends
  • cljs.core on the javascript side would become cljs.js.core, which could make existing applications break

A solution both those problems would be to alias the namespace automatically to cljs.core

Option 2 : Only move compile-time cljs.core to a backend specific namespace

Pros

  • No problems clojurescript side
  • We don't expose the multiple backends

Cons

  • Harder to get right on the compiler's side, which has now to account for the fact that there is both a cljs.core and a cljs.js.core, which are basically the same stdlib, but cljs.js.core is the compile-time macros part of it.

I personnally think the first option is a better option, if there is a way to make the stdlib still exposed as cljs.core in the end, which i think should be possible.


Side problem : How to parametrize

The question is then, how the user would choose which namespace to use ?

Dynamic var works ok, but is not very explicit.

We could use a dynamic var internally, but require the namespace name to be passed explicitly in function parameters for the publically exposed functions ?

Labels:
  1. Jun 13, 2012

    I'm not a fan of option 1. I think the namespaces should be left alone. I don't even think having ClojureScript ship with multiple backends out of the box is a necessary goal.

    What I would prefer to see is that people can easily bring their own backend and ClojureScript does not get in their way.

  2. Jun 13, 2012

    I agree about the multiple backends.

    The problem is that it is necessary that macro-expansion is done before analysis, so in making the compiler modular, we need to perform macro-expansion that is aware of the backend specific macros. That's where the whole problem come from, if it was just for emitters, there wouldn't be no problem.

    1. Jun 13, 2012

      Is that not addressed in my code snippet? Macros will no longer be loaded automatically in compiler.clj. Backends will need to load them explicitly. It must be a file that defines cljs.core as a namespace.

      1. Jun 14, 2012

        Ha ok, sorry i didn't understand the implications of the load-macros.

        This solution is good, it has the merit to be simple to implement too. A couple things bother me though:

        • The flow of execution is not gonna be very clear in alternative backends.
          • If the (require cljs.core) is still in cljs.compiler there is also the risk that while you have not finished implementing your macros, you still have some stray cljs.core macros that have been imported with cljs.compiler
          • If the (require cljs.core) isn't in cljs.compiler, you have a module that doesn't make sense by itself (you can call analyze, but it will use all of clojure.core macros ? Or maybe you exclude them so that it errors out if you didn't load macros ?)
        • You're bypassing the namespace mechanism and using a path based mechanism for loading macros instead. I'm really not sure i like that, using paths has all sort of ugly corner cases that i'd rather not deal with.

         

        I have an alternative solution :

        • Replace all references to cljs.core in the parser/analyzer/etc to references to a dynamically bound var *core-ns*
        • Bind this var to 'cljs.core by default, so that the compiler works as is with the js backend by default

        I have a working solution along the lines of this, which works with the current compiler, and appears to work if you provide a different core namespace. What do you think ?

        1. Jun 14, 2012

          I've thought about this some. I do not think it's a good idea to parameterize the core namespace. All backends should be able to compile cljs.core (the library) out the door. There are only a few cases in there now that are JS-centric in any way. We should eliminate these or parameterize them.

          Another benefit of not allowing people to parameterize the core namespace is that it aids in portability. I would like my CLJS code to just work on Lua.

          I think errorring out when calling analyze without loading a macros files is fine.

          1. Jun 14, 2012

            Allright, i can see the benefits of this option, i'm gonna do it this way then !

          2. Jun 15, 2012

            I think i found a good solution to that. I submitted a patch on JIRA, using the load function (classpath relative) when needed, and the load-file function (filesystem) when wanted, that way you can set it up in a way that makes sense for your project.

  3. Jun 13, 2012

    I agree about the multiple backends.

    The problem is that it is necessary that macro-expansion is done before analysis, so in making the compiler modular, we need to perform macro-expansion that is aware of the backend specific macros. That's where the whole problem come from, if it was just for emitters, there wouldn't be no problem.