This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-18
Channels
- # ai (6)
- # announcements (3)
- # babashka (5)
- # beginners (22)
- # calva (1)
- # cider (3)
- # clj-kondo (30)
- # clj-yaml (20)
- # clojure-europe (83)
- # clojure-spec (4)
- # clojurescript (6)
- # fulcro (1)
- # graalvm (16)
- # holy-lambda (5)
- # malli (33)
- # music (1)
- # nbb (14)
- # releases (3)
- # sci (13)
- # scittle (3)
- # shadow-cljs (35)
- # xtdb (7)
- # yada (2)
Hi. I'm trying ot use a default fn value transformer from the tips section (https://github.com/metosin/malli/blob/master/docs/tips.md#default-value-from-a-function) and also discussed here https://clojurians.slack.com/archives/CLDK6MFMK/p1626171933375100, but sci fails with "could not resolve symbol" with the function i'm using. Any idea why?
; (err) Execution error (ExceptionInfo) at sci.impl.utils/throw-error-with-location (utils.cljc:39).
; (err) Could not resolve symbol: get-num-cpus
got a response from borkdude here, unclear how to proceed though - how to pass a namespace? https://clojurians.slack.com/archives/C015LCR9MHD/p1663501053285409
you can pass in the normal sci-options via :malli.core/sci-options
. what ever sci accepts, is accepted here too:
(m/validate
[:fn '(fn [arg] (malli.impl.util/-invalid? arg))]
::m/invalid
{::m/sci-options {:namespaces {'malli.impl.util {'-invalid? malli.impl.util/-invalid?}}}})
; => true
(defn get-num-cpus []
(-> (Runtime/getRuntime) .availableProcessors))
(m/validate
[:fn '(fn [arg] (= arg (get-num-cpus)))]
10
{::m/sci-options {:namespaces {'user {'get-num-cpus get-num-cpus}}}})
; => true
hmm, i thought i did. don't i? i need to calculate the value based on amount of available cpus
you could also just remove the '
and say #(hash-map :thread-count (* 5 (get-num-cpus)))
m/eval
takes any function or a source code. for the latter, it uses sci to interpret it.
you can’t store normal functions as data (over wire / db etc), but if you don’t need that, you don’t have to use sci.
amazing. i'm going to test that and get back to you.
another question: what if i need to calculate the :default
based on another key's input?
see this example, how can i avoid sci?
[:parallel-pull-count
{:title "Pull messages thread count"
:description ""
:default 1}
pos-int?]
[:ack-and-lease-extension-thread-count
{:title "ACK processing and lease extension thread count"
:description ""
; immitate java-pubsub's default value
;
:default-fn '#(max 6 (* 2 (:parallel-pull-count %)))}
pos-int?]]]])
currently, the transformation interceptors don’t see their parents, so, attaching a transformer into a map key -> just sees that key & it’s children. This could be changed, but would need an issue and some thinking on how to do that.
but, you can attach the default values into the :map
itself -> in that case the default-fn sees the whole map.
yeah but in case the map was given by the user and one of the keys is missing, i want to support defaulting there as well
btw, just tried your suggestion and it doesn't work:
:default #(hash-map :thread-count (* 5 (get-num-cpus)))}
i'm getting
; (out) clojure.lang.ExceptionInfo: Invalid configuration {"parsing_errors" {:concurrency ["invalid type"]}}
the :default
key is defined in the default-value-transformer
and it should be a value, e.g. (hash-map :thread-count (* 5 (get-num-cpus)))
. the default-fn-value-transformer
defines a key :default-fn
which can be a function, e.g. #(hash-map :thread-count (* 5 (get-num-cpus)))
.
(m/decode
[:map {:default {}}
[:x {:default (get-num-cpus)} string?]
[:y {:default-fn #(* (get-num-cpus) (:x %))} string?]]
nil
(mt/transformer
(mt/default-value-transformer)
(default-fn-value-transformer)))
; => {:x 10, :y 100}
> currently, the transformation interceptors don’t see their parents, so, attaching a transformer into a map key -> just sees that key & it’s children. This could be changed, but would need an issue and some thinking on how to do that. Interesting. That’s just the issue I was struggling with 😅 Should I create an issue?
To be more specific, I’m trying to get the name in the key of a :map-of
construct, and use it as a default for one of the values in a sub-map