babashka/sci

No context found in: sci.ctx-store/*ctx* with (map find-ns ['user]))

Closed this issue · 3 comments

Version

0.10.47

Platform

Linux, JVM

Problem

No context found in: sci.ctx-store/ctx with (map find-ns ['user])).
Here find-ns fails in lazy evaluations context of map, works fine with the strict mapv

repro

(defn- eval-sexp [sexp]                                                                                                                                       
  (eval-string (str sexp)))

(eval-sexp '(map find-ns ['user]))   ; => No context found in: sci.ctx-store/*ctx*                                                                                                
(eval-sexp '(mapv find-ns ['user]))  ; => [#object[sci.lang.Namespace 0x54f40d66 "user"]]                                                                    

;; Even without `find-ns` we still do need strict `mapv` here:                                                                                              
(eval-sexp
 '(let [ns-objects (all-ns)
        dirs (mapv clojure.repl/dir-fn ns-objects)]
    (map count dirs))) ; => (0 563 12 3 2 10 21 10 2)

expected behavior

map and mapv return the same sequence elements

See the use case
https://github.com/alexei-matveev/genko/blob/master/src/genko/sci.clj#L29

And thank you for the great product!

Hey @alexei-matveev!

The evaluated expression returns a lazy sequence. When this is evaluated SCI normally uses the context it creates or is passed explicitly (in the case of eval-string*). But since the expression is lazy, the context goes out of scope.

You can read more about it here:

https://github.com/babashka/sci/blob/master/CHANGELOG.md#01046-2025-06-18

and here:

https://github.com/babashka/sci?tab=readme-ov-file#laziness

One solution could be to make an explicit context and set it as the global context with sci/reset-ctx.

Thanks! The second link, https://github.com/babashka/sci?tab=readme-ov-file#laziness, was eye opening. Forcing the lazy seq in the SCI context did the trick.
In fact the advice from the error message to use sci.ctx-store/reset-ctx! is kinda
red herring, after the fact. The issue was indeed that we continue evaluating
lazy seq after leaving SCI context:

  ;; Number of bindings pro namespace. NOTE: `doall` *inside* SCI is                                                                                          
  ;; important for lazy sequence such as the `for`-expression here!                                                                                           
  ;; once you leave the dynamic context of the SCI you cannot count on                                                                                        
  ;; daynamic `*ctx*` having a correct value!                                                                                                                 
  ;;                                                                                                                                                          
  ;;     (eval-sexp '(for [ns ['user]] (find-ns ns)))   ; WRONG!                                                                                              
  ;;     => Exception with "No context found in: sci.ctx-store/*ctx* ..."                                                                                     
  (eval-sexp
   '(doall
     (for [ns (all-ns)]
       [(str ns) (count (clojure.repl/dir-fn ns))])))
  =>
  (["user" 0]
   ["clojure.core" 563]
   ["clojure.set" 12]
   ["Math" 3]                           ; 0 <> 3 without `doall`                                                                                              
   ["clojure.edn" 2]
   ["clojure.repl" 10]
   ["clojure.string" 21]
   ["clojure.walk" 10]
   ["clojure.template" 2])

  ;; Alternatively use `mapv` instead of lazy seq:                                                                                                            
  (eval-sexp
   '(let [ns-objects (all-ns)
          dirs (mapv clojure.repl/dir-fn ns-objects)]
      (map count dirs))) => (0 563 12 3 2 10 21 10 2)

Glad to have answered your question