Fork me on GitHub
#sci
<
2020-11-06
>
katox14:11:32

I bumped into this:

(sci/eval-string "(require '[clojure.set :as set]) (set/union {}{})" opts)
=> {}
but
(sci/eval-form (sci/init {}) (edn/read-string "(require '[clojure.set :as set]) (set/union {}{})"))
Execution error (ExceptionInfo) at sci.impl.utils/throw-error-with-location (utils.cljc:52).
Could not resolve symbol: clojure.set
how can I interpret a form previously read by edn/read-string ? Or do I have to use the sci version?

borkdude14:11:47

let me take a look

borkdude14:11:53

@katox ah I see. the EDN you read is not well-formed as clojure code due to EDN supporting quotes as single things, they are not related to what follows. It's just an ordinary symbol.

user=> (edn/read-string "'[1 2 3]")
'
compare:
user=> (def form (read-string "(do (require '[clojure.set :as set]) (set/union #{1 2} #{2 3}))"))
#'user/form
user=> (sci/eval-form (sci/init {}) form)
#{1 3 2}

katox14:11:58

hmm, if I replace the quote symbol with the actual quote function it still doesn't do the thing

borkdude14:11:57

@katox

user=> (def form (edn/read-string "(do (require (quote [clojure.set :as set])) (set/union {}{}))"))
#'user/form
user=> form
(do (require (quote [clojure.set :as set])) (set/union {} {}))
user=> (sci/eval-form (sci/init {}) form)
{}

borkdude14:11:08

edn/read-string only reads the first form

katox14:11:59

what was the original problem - it was a "configuration" file with two functions in it

katox14:11:24

i wanted to read it in with edn and run those functions through sci (only those)

katox14:11:46

what approach would you use? just read it all using sci parser?

borkdude14:11:04

@katox I think you can also use edamame for this: it allows parsing EDN++, where ++ is just the amount you need

katox14:11:19

edn++, nice 😄

borkdude14:11:26

but you can also just use the sci parser for this

katox14:11:09

things like these get tricky soon, you must have a galaxy brain

katox14:11:42

thanks a lot, I'll try to get that in

katox14:11:17

another thing - is there a convenience function to import the whole ns into sci :namespaces ?

borkdude14:11:37

not really, but you can do this using ns-publics + sci/copy-var

katox14:11:26

I use this

(defn map-sym [ns syms]
  (into {} (map (fn [sym] [sym @(resolve (symbol (name ns) (name sym)))]) syms)))
but kinda too simplistic 🙂

borkdude14:11:08

that works too. note that if you're compiling down to a native-image, having resolve in a function body isn't great for size

borkdude14:11:39

but if you're doing this on the top-level it should not be a problem

katox14:11:20

the ns will be compiled in, the require is there only to alias syms

katox14:11:12

will alias be better?

borkdude14:11:32

@katox What I mean is: if you use map-sym only on top-level values, that's ok, but if you use this at run-time in the graalvm binary, it will add 10-20 MB to the binary for nothing

borkdude14:11:37

Resolve holds on to too much stuff, this is why you will get a fatter binary

katox14:11:57

I see it's about the resolve function itself

borkdude14:11:58

yes. so:

(def my-namespace (map-sym ...))
is good, but:
(defn foo [x] (get (map-sym ...) x))
is not that great for binary size.

borkdude14:11:15

A relatively simple graalvm binary with java 11 and clojure 1.10.2-alpha3 yields about 11mb. When you accidentally use resolve at runtime it will become 25mb.

katox14:11:37

The first could do, it's a constant environment. I am just too lazy to enumarate the whole libary ns and top level syms. ns-publics + copy-var should do the same thing (if all symbols are imported)

borkdude14:11:00

yeah, generating a constant at compile time, that's the way to do it.

👍 3
borkdude14:11:29

sounds like that works fine.

katox14:11:29

thanks for insights