sci

https://github.com/babashka/SCI - also see #babashka and #nbb
borkdude 2020-07-21T09:04:07.327700Z

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

๐Ÿ™Œ 1
ikitommi 2020-07-22T17:18:29.328300Z

cool, works.

ikitommi 2020-07-22T17:18:54.328500Z

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

borkdude 2020-07-22T17:19:23.328700Z

I don't think so?

ikitommi 2020-07-22T17:19:41.328900Z

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

ikitommi 2020-07-22T17:20:05.329100Z

I guess itโ€™s intentional?

borkdude 2020-07-22T17:20:34.329300Z

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

ikitommi 2020-07-22T17:21:18.329600Z

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

borkdude 2020-07-22T17:22:26.329800Z

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

ikitommi 2020-07-22T17:22:34.330Z

ok

borkdude 2020-07-22T17:23:04.330200Z

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

borkdude 2020-07-22T17:25:00.330400Z

let me try

borkdude 2020-07-22T17:26:27.330600Z

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.

borkdude 2020-07-22T17:27:48.330800Z

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

borkdude 2020-07-22T17:28:12.331Z

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

borkdude 2020-07-22T17:29:43.331200Z

Guess that covers the typical malli use case

borkdude 2020-07-21T20:22:21.328100Z

@ikitommi FYI ^