sci 2022-04-29

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

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:

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

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

@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

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

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

👍 1

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

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

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

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

(in this context, I mean)

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

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!

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

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

oops, sorry ) too many channels )

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

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

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

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

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

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

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

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.

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

but is find-ns something you were looking for?

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

Yes, that would work perfectly in my case!

good, just a minute then

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?

(or is there a better way to enumerate namespaces)

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

@pmooser

b2e1354c7a24ce22d5f5b8a901d3c39cd0c8baf3

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

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

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

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

fcf7e6067f091fd2cf2843660349e820c4449dd8

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

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*

Let me see what it says inside binding but before eval

So that happens even before I call eval.

Please be more precise, make a code example

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

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

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

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

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

the following println

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

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

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

Sorry and thank you.

No problemo

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

👍 1