leonoel / cloroutine

Coroutine support for clojure
Eclipse Public License 2.0
228 stars 10 forks source link

undeclared cloroutine.impl/coroutine when requiring from clojurescript #4

Closed fonghou closed 5 years ago

fonghou commented 5 years ago

I tested the asyncawait.clj/cljs code from here. For some reason, always get below compile error ("cloroutine is not defined" runtime error as well). It might have something to do with the implicit require-macros I did in async.cljs file, but I really couldn't figure out where it went wrong (strangely, no other vars referred by the macro expansion from cloroutine.impl namespace get that error).

  10 | (defn test-async []
  11 |   (async!
---------^----------------------------------------------------------------------
 Use of undeclared Var cloroutine.impl/coroutine
--------------------------------------------------------------------------------
  12 |    (let [ok (await (js/Promise. #(%1 "success")))
  13 |          err (try (await (js/Promise. #(%2 "error")))
  14 |                   (catch :default _ :error))]
  15 |      (js/console.log ok)

src/cloroutine/async.cljs

(ns cloroutine.async
  (:require-macros cloroutine.async))

(def ^:dynamic *success*)
(def ^:dynamic *failure*)
(def ^:dynamic *status*)
(def ^:dynamic *result*)

(defn await [p]
  (.then p *success* *failure*))

(defn thunk []
  (if *status* *result* (throw *result*)))

(defn spawn [c]
  (letfn [(run []
            (binding [*success* success
                      *failure* failure]
              (c)))
          (success [x]
                   (binding [*status* true
                             *result* x] (run)))
          (failure [x]
                   (binding [*status* false
                             *result* x] (run)))]
    (run)))

src/cloroutine/async.clj

(ns cloroutine.async
  (:refer-clojure :exclude [await])
  (:require [cloroutine.core :refer [cr]]))

(defmacro async! [& body]
  `(js/Promise. (fn [s# f#]
                  (spawn (cr {await thunk}
                             (try (s# (do ~@body))
                                  (catch :default e# (f# e#))))))))
fonghou commented 5 years ago

adding (:require [cloroutine.impl]) in async.cljs file appears to resolve it. not sure why it's needed. it may has something to do with shadow-cljs since it tracks cljs namespace dependencies base on these require clauses.

leonoel commented 5 years ago

Adding a (:require [cloroutine.core]) clause to the cljs part is required because the cr macro emits code that relies on a runtime helper function.

I don't recommend requiring cloroutine.impl directly because it's not part of the public API. cloroutine.core will transitively require cloroutine.impl so it should be preferred.

I'm not familiar with shadow-cljs but I doubt it's related to this problem.