Fork me on GitHub
#sci
<
2020-07-21
>
borkdude09:07:07

Implemented #369 as follows: > In a multi-user environment it can be useful to give each user their own > context. This can already be achieved with eval-string, but for performance > reasons it may be desirable to initialize a shared context. This shared context > can then be forked for each user so that changes in one user's context > aren't visible for other users:

(def forked (sci/fork sci-ctx))
(sci/eval-string* forked "(def forked 1)")
(sci/eval-string* forked "forked") ;;=> 1
(sci/eval-string* sci-ctx "forked") ;;=> Could not resolve symbol: forked

🙌 3
ikitommi17:07:29

cool, works.

ikitommi17:07:54

if one has handle to the original ctx and adds anything to it, it will be visible to all future forks.

borkdude17:07:23

I don't think so?

ikitommi17:07:41

(let [ctx (init nil)]
  (eval-string* ctx "(def secret 123)")
  (eval-string* (fork ctx) "{:secret secret}"))
; => {:secret 123}

ikitommi17:07:05

I guess it’s intentional?

borkdude17:07:34

yes, the fork is based on the context at the time you forked it

ikitommi17:07:18

added this to malli, maybe it could be on sci side?

(defn evaluator [options]
  (let [ctx (init options)]
    (fn eval [s]
      (eval-string* (fork ctx) s))))

borkdude17:07:26

I don't think that's necessary to add any combination of API functions back into the API itself

borkdude17:07:04

There is one edge case, when you add your own vars to the initial context, users may or may not be able to alter-var-root things. I have to think more about this

borkdude17:07:27

So the core vars are OK:

user=> (sci/eval-string* (sci/fork ctx) "(alter-var-root #'clojure.core/inc (constantly dec))")
Execution error (ExceptionInfo) at sci.impl.vars.SciVar/bindRoot (vars.cljc:250).
Built-in var #'clojure.core/clojure.core/inc is read-only.

borkdude17:07:48

And this is also OK:

user=> (def ctx (sci/init {:profile :termination-safe :bindings {'x 1}}))
#'user/ctx
user=> (sci/eval-string* (sci/fork ctx) "(alter-var-root #'x (constantly dec))")
Execution error (IllegalArgumentException) at sci.impl.vars/eval448$fn$G (vars.cljc:156).
No implementation of method: :getRawRoot of protocol: #'sci.impl.vars/IVar found for class: java.lang.Long

borkdude17:07:12

So as long as you don't use sci vars in your options (which are mutable like Clojure vars) you are OK

borkdude17:07:43

Guess that covers the typical malli use case