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

Better cloning? #58

Open
metasoarous opened this issue Mar 6, 2017 · 2 comments
Open

Better cloning? #58

metasoarous opened this issue Mar 6, 2017 · 2 comments

Comments

@metasoarous
Copy link
Owner

We have a really cool semantic-csv.impl.core/clone-var macro that expands to a def which refers to the original var, but copied over the docstring, argslist and everything. I don't have the patience right now to get something that does "the best we can" in making this cross compatible with cljs, because portable cljs macros are nutty af. I did a little work in this direction though, and here are some of the things I've come up with:

This would maybe be the most conservative thing, and seems to work for the clj side at least. I don't yet know however if the cljs part works (either ClojureScript JVM or ClojureScript JS). There's a good chance it may not for the reasons mentioned in the portable cljs blog post (the reader cond is expanding at macro compile time, so thing may not work quite right there for JVM targeting JS, but JS targeting JS might).

(defmacro clone-var
  "Clone the var pointed to by fsym into current ns such that arglists, name and doc metadata are preserned."
  [fsym]
  #?(:clj
     (let [v (resolve fsym)
           m (subset-map (meta v) [:arglists :name :doc])
           m (update m :arglists (fn [arglists] (list 'quote arglists)))]
       `(def ~(vary-meta (:name m) (constantly m)) ~fsym))
     :cljs
     `(def ~(symbol (name fsym)) ~fsym)))

There's also the following, which tries to use the tricks from the above blog post, but it isn't even working for clj as is. And the blog post is kind of focused on a particular part of the general problem which is getting the vars to resolve properly.

(defmacro clone-var
  "Clone the var pointed to by fsym into current ns such that arglists, name and doc metadata are preserned."
  [fsym]
  `(if-cljs
     ~(let [v (resolve fsym)
            m (subset-map (meta v) [:arglists :name :doc])
            m (update m :arglists (fn [arglists] (list 'quote arglists)))]
        `(def ~(vary-meta (:name m) (constantly m)) ~fsym))
     `(def ~(symbol (name fsym)) ~fsym)))

I'm not really interested in optimizing this any more until we get some cljs testing set up with doo or whatever (see #56). For now I'm just going to do a top level reader conditional that decides whether to manually call (def the-var path.to.actual/the-var) a bunch of times, or use the macro. The only downside is loosing docstrings for cljs, which isn't the end of the world.

(Relates to #45)

@mahinshaw
Copy link
Contributor

One of the tricks for this is going to deal with var resolution. Cljs does not have a resolve function. However, cljs.analyzer.api does have a resolve. But it returns an analyzer map, which is good for cljs, but it will lead to a different implementation in cljs. It may just be best to implement this method seperately for cljs to solve to bootstrapped cljs issue.

@metasoarous
Copy link
Owner Author

It would be cool if we could wrap them up into one macro so that we can point people to it (I know I've wanted this macro before). But either way is fine really.

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

No branches or pull requests

2 participants