Fork me on GitHub
#sci
<
2022-04-29
>
pmooser09:04:16

So I apologize - I didn't mean to privately message you before about how to manage namespaces when coding a repl using sci - you very kindly replied with the following code:

(def !last-ns (volatile! @sci/ns))

(defn eval-string [s]
  (sci/binding [sci/ns @!last-ns]
    (let [rdr (sci/reader s)]
      (loop [res nil]
        (let [form (sci/parse-next @!ctx rdr)]
          (if (= :sci.core/eof form)
            (do
              (vreset! !last-ns @sci/ns)
              res)
            (recur (sci/eval-form @!ctx form))))))))

pmooser09:04:41

I'm not using that code quite yet, but if I try something like (ns client) in my repl, I get the following error, and I'm curious what's causing it:

pmooser09:04:07

Can't change/establish root binding of #'clojure.core/*ns* with set

pmooser09:04:36

Maybe if I used the code you showed, that somehow wouldn't happen but if that's the case, I'm confused.

borkdude09:04:41

@pmooser The problem is that (ns client) will change the value of the dynamic var *ns* but it may only be changed inside a binding. eval-string and eval-string* do that automatically, but eval-form does not

borkdude09:04:32

With "do that automatically" I mean: they surround the evalution with a binding

pmooser09:04:35

So is it sufficient for me just to bind (using sci/binding ) ... sci/ns ?

👍 1
borkdude09:04:45

which also means that the value of *ns* is restored after the binding

pmooser09:04:50

Or do I need to use "normal" (cljs) binding of *ns* ?

pmooser09:04:04

Ok great - that does indeed fix it. Now I'll integrate the rest of what you gave me. Thanks - I have things almost perfectly working I think ...

pmooser10:04:16

@borkdude In cljs, what's the practical difference between using a volatile vs. storing a value in an atom ?

pmooser10:04:21

(in this context, I mean)

borkdude11:04:41

@pmooser volatile is a light weight atom with less features and therefore a bit more performant

pmooser14:04:45

Sure, but given that performance in a repl (between entered data) is sort of gated by typing speed, it seems like that difference isn't materially important here. In any case, it sounds like it isn't required, but I appreciate the additional info!

delaguardo11:04:40

"less features" means not thread safe and should be used only in isolation.

borkdude11:04:01

yes, but we're talking CLJS here so threads are not a concern

delaguardo11:04:56

oops, sorry ) too many channels )

borkdude11:04:25

With "here" I mean in the context of @pmooser’s question, not this channel > In cljs, what's the practical difference

pmooser14:04:35

Given a sci context, is there a way to say "what is the sci namespace for symbol x " ?

pmooser14:04:01

(outside of sci itself ... I'm trying to put bindings together for the very first call to the sci evaluator ... once I've been through there, it's not really a problem)

pmooser14:04:15

I suppose I could eval something and get sci to return the namespace, but it seems like there must be a better way.

borkdude14:04:02

@pmooser There currently isn't a better way than eval-ing something :) But I guess we could expose (sci/find-ns ctx sym)?

borkdude14:04:12

I've needed that myself too. I could do that right now

pmooser14:04:59

I suppose I shouldn't be afraid of eval-ing something - I just have written my own interface (since my use of sci is an adaptation of something I used to have) and I have a symbol in hand which corresponds to the namespace I want, but the actual place the namespace gets created is "somewhere else" (where I'm creating namespaces and copying existing cljs namespaces), so what I have easy access to is simply the ctx ...

pmooser14:04:26

I also don't know enough about the sci representation of namespaces to do anything other than call "eval" safely, since I don't know exactly how they evolve over time.

borkdude14:04:38

indeed, the representation inside the context is subject to change, but the outer API should remain stable

borkdude14:04:49

but is find-ns something you were looking for?

borkdude14:04:01

(find-ns ... ...) -> SCI ns object?

pmooser14:04:09

Yes, that would work perfectly in my case!

borkdude14:04:28

good, just a minute then

pmooser14:04:05

Do you think it's sufficiently "safe" (from an API stability point of view) to do something like: (keys (:namespaces @(:env sci-ctx))) to find the list of namespace (symbols) that sci knows about?

pmooser14:04:21

(or is there a better way to enumerate namespaces)

pmooser14:04:31

This isn't a vital feature, but I was curious.

borkdude14:04:11

@pmooser

b2e1354c7a24ce22d5f5b8a901d3c39cd0c8baf3

borkdude14:04:51

@pmooser There is a better way, which is to evaluate (all-ns) - I could also expose that one, just a moment

pmooser14:04:18

It's really nice to be able to enumerate namespaces on the cljs side.

borkdude14:04:10

@pmooser Something like this?

user=> (require '[sci.core :as sci])
nil
user=> (def ctx (sci/init {}))
#'user/ctx
user=> (def all-nss (sci/all-ns ctx))
#'user/all-nss
user=> (map sci/ns-name all-nss)
(user clojure.core clojure.set clojure.edn clojure.repl clojure.string clojure.walk clojure.template)

pmooser14:04:34

Yup, I think that would work great for my purposes.

borkdude14:04:17

fcf7e6067f091fd2cf2843660349e820c4449dd8

pmooser14:04:20

Thank you ... trying some of this out (it may take me a little bit)

pmooser14:04:59

Ok, I imagine I'm doing something wrong. So I create my namespaces and I have my context. Then I pull out a specific namespace (based on a config file), which in this case is user: (sci/find-ns sci-ctx (:default-ns repl-config)) That returns the right ns, which has the right name. However, when I call sci to evaluate something, I set up bindings like this:

(sci/binding [sci/ns (:current-ns @state)] ...)
And when I call eval, after I do the eval, if I ask sci/ns for its name, I get *ns*

pmooser15:04:06

Let me see what it says inside binding but before eval

pmooser15:04:00

So that happens even before I call eval.

borkdude15:04:10

Please be more precise, make a code example

pmooser15:04:15

Yes, one moment.

pmooser15:04:00

(let [ns (sci/find-ns (:sci-env @state) 'user)]
  ;; prints "user"
  (println "1: name ns" (sci/ns-name ns))
  (sci/binding [sci/ns ns]
    ;; prints "*ns*"
    (println "2: name ns" (sci/ns-name sci/ns))))

borkdude15:04:47

The result of (sci/ns-name ns) prints *ns* ?

pmooser15:04:20

The result of sci/ns-name (as shown in the code snippet you requested) is "user".

borkdude15:04:15

I don't get to which part "`;; prints "ns""` refers to

pmooser15:04:16

(sci/ns-name ns) --> "user" (sci/ns-name sci/ns) --> *ns*

pmooser15:04:20

the following println

pmooser15:04:32

Each comment above the println that says "prints" says what the print does

borkdude15:04:38

yes, this is expected. sci/ns is a SCI var. you should first deref it

pmooser15:04:25

Yes, I see you do that in your code example you kindly provided. It just went over my head.

pmooser15:04:34

Sorry and thank you.

borkdude15:04:51

No problemo

pmooser15:04:34

Make sense?

pmooser15:04:48

@borkdude Ok, I can confirm both changes are working for me (all-ns and find-ns).

👍 1