Fork me on GitHub
#sci
<
2022-09-27
>
Lone Ranger18:09:06

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"}

Lone Ranger18:09:05

the rest of core.async works, it's just not happy about the channels

Lone Ranger19:09:49

ok think I have a workaround

borkdude20:09:42

Are you trying to use core.async with SCI?

borkdude20:09:57

in CLJS, I mean?

Lone Ranger20:09:29

I have the most horrible hack

borkdude20:09:47

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

borkdude20:09:27

The core.async go macro is a bit too complicated for my taste to use in CLJS

borkdude20:09:46

but if you got it working, I'm interested :-)

Lone Ranger20:09:50

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#)))

borkdude20:09:50

could you describe in words what you did there? :)

Lone Ranger20:09:12

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 machinery

Lone Ranger20:09:52

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)})}}))

Lone Ranger20:09:03

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)))))))

Lone Ranger20:09:08

and data resolves to 4

Lone Ranger20:09:45

I'm not gonna pretend it's elegant 😅

Lone Ranger20:09:56

I just don't want to have to write thousands of lines of core.async code to promesa

borkdude20:09:50

if it works for you, it's fine :)

Lone Ranger21:09:09

ah sadly this does not actually work

Lone Ranger21:09:28

it breaks down when a/<! gets involved. That's alright, it will be a useful constraint

Lone Ranger22:09:28

yeah promesa was a great recommendation, the switch is rather painless

Lone Ranger23:09:16

that's a lot of work!!

mkvlr11:09:36

@U04V15CAJ but it should be possible and not hard to get core.async working with sci, right?

mkvlr11:09:01

might need a lot of copying I guess so more annoying work rather than being complicated, right?

borkdude12:09:48

@U5H74UNSF 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.

👍 1
borkdude12:09:53

just use promises on JS