Fork me on GitHub
#malli
<
2024-06-12
>
lambdam09:06:25

Hello everyone I spontaneously tried to define local registries with namespaceless keywords, like so:

(ns my-ns
  ...)

(def local-registry
  {:api-key :string
   :values [:sequential :string]
   :output [:fn other-ns/plop?]})

;; When using the local registry in a :map schema, I get the following ExceptionInfo when compiling the form:
;; :malli.core/register-function-schema
(m/=> foo
  [:=> [:cat [:map {:registry local-registry}
              :api-key :values]]
   :any])

(defn foo [m] ...)

;; This compiles well with the return value of the :=> schema being defined only in local registry
(m/=> bar
  [:=> {:registry local-registry}
   [:cat [:map [:api-key string] [:values [:sequential :string]]]]
   :output])

(defn bar [m] ...)
1. I saw in the documentation that local-registry keys should be namespaced keywords or strings. Why does this seem to work for the :=> and not for the :map schema? 2. Why not allowing namespaceless keys in local registries? 3. When exposing a local registry to a schema, does it scope this local registry to sub schemas? Example in [:=> {:registry local-registry} [:map ... does the :map schema "sees" the same schemas than the :=> schema, ie global registry + local registry? And thus would scopes of local registries be scoped like variables in Clojure in nested let expressions? Thanks a lot

ambrosebs16:06:20

1. your syntax seems off, please post the full error. 2. a local registry is scoped dynamically so it is effectively a global variable. namespace qualification mitigates some of the negatives of dynamic scope. 3. yes, it is seen by all subschemas. it's more like binding than let.

ambrosebs16:06:24

I'm guessing local registries are special because they can be rebound dynamically by schemas themselves. Schema registry entries like :=> and :map are provided by the options map, and can't be shadowed (meaningfully) by the local registry, since local registries must be serializable and Schemas are not https://github.com/metosin/malli/pull/1026

lambdam15:06:27

Thanks @U055XFK8V Sorry for late reply 1. This is the error that I get when providing a local registry to :map with non-namespaced keys :

1. Unhandled clojure.lang.ExceptionInfo
   :malli.core/register-function-schema
   {:type :malli.core/register-function-schema,
    :message :malli.core/register-function-schema,
    :data
    {:ns habilitatem.server.handlers.student.orientation-wizard-v2,
     :name student-orientation-wizard-get,
     :schema
     [:=>
      [:cat [:map {:registry {:result :map}} :system/now :datomic/conn]]
      :result],
     :data nil,
     :key :clj,
     :exception #error {
    :cause ":malli.core/invalid-schema"
    :data {:type :malli.core/invalid-schema, :message :malli.core/invalid-schema, :data {:schema :result, :form :result}}
    :via
    [{:type clojure.lang.ExceptionInfo
      :message ":malli.core/invalid-schema"
      :data {:type :malli.core/invalid-schema, :message :malli.core/invalid-schema, :data {:schema :result, :form :result}}
      :at [malli.core$_exception invokeStatic "core.cljc" 136]}]
    :trace
...
But when I provide the local registry to the :=> schema I do not get this error, and only when using the => macro. When using metadatas and collect, I do get the error. 2 & 3 I think I don't get the subtleties of global variables and binding vs let I was thinking more about the shadowing ability of let and the fact of exposing a schema in a scope like let exposes a variable in a scope. 2. "a local registry is scoped dynamically so it is effectively a global variable" : since a local registry can be defined inline, how is it comparable to a global variable? 2. again; "namespace qualification mitigates some of the negatives of dynamic scope": how bad would it be to redefine locally a schema? Thanks a lot