Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minimal example #1

Open
viebel opened this issue Dec 27, 2016 · 6 comments
Open

Minimal example #1

viebel opened this issue Dec 27, 2016 · 6 comments

Comments

@viebel
Copy link

viebel commented Dec 27, 2016

Hi @cgrand

macrovich is a great tool that will help the clojure community to port a lot of clojurescript libs to bootstrap cljs

For instance datascript.

I’m really excited because it means that we will be able to have all those great libs running in the browser with klipse!

I started to play with macrovich

But I’m a bit confused about what problem exactly macrovich solves

I have created a minimal repo
with two macro files:

  1. without macrovich

  2. with macrovich

File #1 seems to work fine in all 3 envs:

  1. clojure
  2. clojurescipt
  3. bootstrap cljs

So in what (simple) cases do we need macrovich?

@cgrand
Copy link
Owner

cgrand commented Jan 3, 2017

There's obviously nothing in macrovitch you can't do by hand. Its goal is to alleviate the pain of making code work in Clojure and the two Clojurescript flavors.

I created these macros to help porting xforms from clj to cljs and self-hosted cljs.
Would I have started from a cljs lib the story would have been different (macros would have been in their own ns for example).

I encountered two issues:

  • determining in which stage code is running (because xforms doesn't segregate macros into their own namespace),
  • determining what is the target dialect.

Determining the stage

In Clojure there's none, so it's always the right time to run some code.

In Clojurescript, it's easy: just use reader conditionals (like you did in your example).

In self-hosted Clojurescript: the file is going to be evaluated twice (once in pseudo $macros namespace and once "for real"). Doing twice the work doesn't help with compilation time and I remember running in some other problems and solving them by preventing non-macro related code to be evaluated in the $macros pseudonamespace.

Macro Clojure Clojurescript Self-hosted Cljs
deftime expands to do expands to do on the Clojure side, to nil on the Clojurescript side expands to do in the $macros pseudonamespace, to nil in the regular namespace
usetime expands to do expands to do on both sides expands to nil in the $macros pseudonamespace, to do in the regular namespace

Determining the target dialect

This problem is specific to Clojure and clojure-hosted Clojurescript: as macros definitions are read by Clojure in both cases, for any reader conditional inside the macro definition this is the :clj branch which is selected. That's the problem solved by macros/case.

As a macros can be invoked from Clojure or Clojurescript the target dialect can't be determined statically.

@viebel
Copy link
Author

viebel commented Jan 3, 2017

Thanks @cgrand for the detailed explanations.
The intent of my question was not to say that macrovich is not required.
The opposite is the true. I am very interested in having a lot of libs self-host compatible (to be able to run them in klipse).

Actually, I have tried to port several lib to be self-host compatible and it was very hard. The only one I was able to port successfully is core.match. Here is the JIRA ticket and the PR.

But still I feel I need a concrete simple example that demonstrates the need for deftime and usetime....

@cgrand
Copy link
Owner

cgrand commented Jan 3, 2017

@viebel from a cursory glance at your PR, I think you have introduced some bugs when run under "regular" Clojurescript. I believe backtrack-expr and FailureNode are going to emit the Clojure version.

@viebel
Copy link
Author

viebel commented Jan 3, 2017

Thanks @cgrand. Could you write this remark in the jira ticket?

@cgrand
Copy link
Owner

cgrand commented Jan 3, 2017

And if I'm right it's an interesting case not covered (yet) by macrovich/case.
Also your PR imported too much from clojure.core.match.

@cgrand
Copy link
Owner

cgrand commented Jan 3, 2017

Having spent some time trying to make macros/case support your case (helper functions for macros) I do realize that it already does. The trick is to never call it from the helper function but to put it into the expansion.

(defrecord FailNode []
  INodeCompile
  (n-to-clj [this]
    (if *recur-present*
      `(throw
         (macros/case
            :cljs
            (js/Error. (str "No match found."))
            :clj
            (Exception. (str "No match found."))))
      (backtrack-expr))))

and

(defn backtrack-expr []
  `(macros/case
     :cljs
     (throw cljs.core.match/backtrack)
     :clj
     (throw clojure.core.match/backtrack)))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants