alright what am I doing wrong here (clojurescript environment)
(ns demo.sidecar
(:require [cljs.core.async :as a]
[cljs.core.async.interop :as ai]
[sci.core :as sci]))
(def ctx (sci/init {:classes {'js goog/global}
:namespaces
{'cljs.core.async
(sci/copy-ns
cljs.core.async
(sci/create-ns 'cljs.core.async))
'cljs.core.async.interop
(sci/copy-ns
cljs.core.async.interop
(sci/create-ns 'cljs.core.async.interop))}}))
(sci/eval-string*
ctx
(apply str
'((ns gogosci.core
(:require [cljs.core.async :as a]
[cljs.core.async.interop :as ai]))
(a/go))))
;;=>
#error
{:cause #error
{:data {:column nil,
:file nil,
:line nil,
:phase "analysis",
:type :sci/error},
:message "Could not resolve symbol: a/go"},
:data
{:column 86,
:file nil,
:line 1,
:message "Could not resolve symbol: a/go",
:phase "analysis",
:sci.impl/callstack
#object
[cljs.core.Volatile
{:val ({:column 86,
:file nil,
:line 1,
:ns #object [sci.lang.Namespace]})}],
:type :sci/error},
:message "Could not resolve symbol: a/go"}
the rest of core.async works, it's just not happy about the channels
ok think I have a workaround
Are you trying to use core.async with SCI?
in CLJS, I mean?
yaya
I have the most horrible hack
For CLJS, I usually recommend using the platform's promises in combination with promesa https://github.com/funcool/promesa There is a configuration here which you can directly use: https://github.com/babashka/sci.configs#funcoolpromesa
The core.async go macro is a bit too complicated for my taste to use in CLJS
but if you got it working, I'm interested :-)
using promesa would be the right thing. But why would you do the right thing when you could do something horrible like this:
(defmacro make-sci-macro-fn
"makes a function with multi arrity dispatch and returns it.
used to make a macro for sci
expands to:
(do (defn fn-name
([a] (sym a))
([a b] (sym a b))
([a ... z] (sym a ... z))
...)
fn-name)"
[fn-name sym]
(let [fn-name# `~fn-name
multi-dispatch-decl# (let [alpha "abcdefghijklmnopqrstuvwxyz"]
[]
(loop [n (dec (count alpha))
res []]
(if (zero? n)
res
(let [args (mapv #(symbol (str %)) (drop-last n alpha))
go-form (list* sym args)]
(recur (dec n)
(conj res
(list args go-form)))))))]
`(do
(def ^:sci/macro ~fn-name# (fn ~@multi-dispatch-decl#))
~fn-name#)))could you describe in words what you did there? :)
It expands to this:
(do (defn ^:sci/macro fn-name
([a] (sym a))
([a b] (sym a b))
([a ... z] (sym a ... z))
...)
fn-name)
which I used in the sci macro machineryok
So I made a context
(def ctx (sci/init {:classes {'js goog/global}
:namespaces
{'cljs.core.async
(merge (sci/copy-ns
cljs.core.async
(sci/create-ns 'cljs.core.async))
{'go (make-sci-macro-fn go a/go)})}}))
then tried it out:
(a/go
(def data
(a/<!
(sci/eval-string*
ctx
(apply str
'((ns gogosci.core
(:require [cljs.core.async :as a]))
(a/go 1 2 3 4)))))))and data resolves to 4
I'm not gonna pretend it's elegant 😅
I just don't want to have to write thousands of lines of core.async code to promesa
if it works for you, it's fine :)
🥳
ah sadly this does not actually work
it breaks down when a/<! gets involved. That's alright, it will be a useful constraint
yeah promesa was a great recommendation, the switch is rather painless
holy crap @borkdude thank you 😮 https://github.com/babashka/sci.configs/blob/main/src/sci/configs/funcool/promesa.cljs#L1
that's a lot of work!!
@borkdude but it should be possible and not hard to get core.async working with sci, right?
might need a lot of copying I guess so more annoying work rather than being complicated, right?
@mkvlr it should be possible, but I don't think it's worth doing so. you need to basically include a CLJS version of tools.analyzer at runtime, etc.
just use promises on JS