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
cool, works.
if one has handle to the original ctx and adds anything to it, it will be visible to all future forks.
I don't think so?
(let [ctx (init nil)]
(eval-string* ctx "(def secret 123)")
(eval-string* (fork ctx) "{:secret secret}"))
; => {:secret 123}
I guess itโs intentional?
yes, the fork is based on the context at the time you forked it
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))))
I don't think that's necessary to add any combination of API functions back into the API itself
ok
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
let me try
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.
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
So as long as you don't use sci vars in your options (which are mutable like Clojure vars) you are OK
Guess that covers the typical malli use case
@ikitommi FYI ^