Hi everyone! I am facing problems using typedclojure with malli custom schemas. Here is a code snipet:
(ns my-project.schemas
(:require [malli.core :as m]
[malli.generator :as mg]
[malli.util :as mu]
[malli.registry :as mr]
[typed.clojure :as t]))
(def my-schema
{::some-schema
[:map
[:key1 string?]]
::some-other-schema
[:map
[:key2 [:ref ::some-schema]]]})
(t/tc-ignore
(mr/set-default-registry! (mr/composite-registry (mr/schemas m/default-registry)
(mu/schemas)
my-schema)))
(defn my-func [arg]
{:key2 {:key1 "test"}})
(m/=> my-func [:=> [:cat ::some-schema] ::some-other-schema])
When checking my namespace with (t/check-ns-clj) , typedclojure do not approve my schema name:
1. Unhandled java.lang.AssertionError
Assert failed: :my-project.schema/some-schema
(re-matches #"^[a-zA-Z]+[a-zA-Z0-9]*$" (name n))
Seems to me this regex do not consider the character '-', it should be something like #"^[a-zA-Z]+[-a-zA-Z0-9]*$" .
Some ideias? Am I doing something wrong?Hi! Could you post the stack trace please?
The odds are that you're not doing something wrong, this is very new.
Ok found it. Really have no idea what I was thinking...did I copy this code from the malli.clj-kondo impl perhaps? https://github.com/typedclojure/typedclojure/blob/94d169ec4cc169b51cca421d0af0d603f58e99a9/typed/malli/src/typed/malli/schema_to_type.cljc#L150
Nope. I have no memory of writing this xD
ah, I bet it was defensive programming against gensyming an invalid symbol from an arbitrary string
Should be fixed by this commit https://github.com/typedclojure/typedclojure/commit/f0d2506f4c982b745fb36cf61e25d4bd4cf92b76 I added your example to the example projects, and I'll schedule a release if the tests pass.
Thanks very much for trying this feature, much appreciated.
Fixed in 1.0.27
Nice!! Ow, my code even became an example! Happy to contribute and thank you very much for the fix!
chef_kiss
I wonder if it makes sense to offer some macros so that the typed-clojure-less "syntax" look even less "almost not horrible". Ie, the metadata shape (to my eyes) appears onerous enough that I'd prob still not be very inclined to use it as a library author, even with the benefit of correctness/analysis/typed-clojure-free-runtime. But a macro or two that (lol) looks like typed-clojure's inline annotation fn macro but expands to the new metadata-based one would have easier ergonomics. Of course, in <insert prod-ish envs here> the macro expands to the underlying fn as-is. You would just need to distribute the macros as a dep that doesn't otherwise contain typed-clojure in any runtime way shape or form. How trivial or useful is the above you think?
You just described the status quo prior to this feature 🙂
typed.clojure/fn is the macro, and it lives in a single jar with no dependencies here: https://github.com/typedclojure/typedclojure/tree/main/typed/clj.runtime
There's a big difference between zero and one dependency when it comes to minimizing dependency hell, it's almost a non starter for many libraries to have dependencies at all.
Anyway, that's my hunch.
Certainly any libs that I wrote I would avoid a direct dependency to Typed Clojure if I used it. So maybe the tradeoff is worth it just for me only 🙂
Now that I've eaten, I see you were suggesting macros that expand to the metadata one. I think that might be just as heavyweight as the real typed.clojure/fn macro, it would need the same parsing logic.`typed.clojure/fn` actually throws away the type annotation too after expansion, because it's never needed at runtime.
The power of the metadata annotations are also that they're compatible with any macro that expands to fn. We don't need to wrap macros endlessly. eg., the argument why defn- doesn't really need to exist because of defn ^:private.
Next I want to support let metadata annotations. That'll be pretty much ann-form.
(let [^{::t/- t/Int} a 1] ...))
many more macros expand to let bindings too, so it'll probably be massive bang for your buck.
@rayatrahman9 sorry about the misread and the wall of text 😬 my attention has been stretched thin, moving house..
how does as-alias work with the symbol t/Int?
surprised that isn't a read/compile error
it reads as {:typed.clojure/- 't/Int} and I don't think it's evaluated. Currently figuring out how this works in CLJS.
user=> (fn [^{:foo (nil)} a])
#object[user$eval40352$fn__40353 0x28a2c41 "user$eval40352$fn__40353@28a2c41"]
The compiler only cares about :tag in Clojure AFAIK.
CLJS seems similar. I don't think any of this is documented behavior.
cljs.user=> (fn [^{:foo (nil)} a])
#object[ret__6855__auto__]
My interpretation is that metadata is generally not evaluated unless it's reified at runtime. That's why this probably won't work using defn's metadata map arg.
Though perhaps using a defn's :arglists might work by annotating defn params.
By the time it gets to Typed Clojure it's basically doing a (binding [*ns* here] (parse-type 't/Int)) and it looks up the current aliases with ns-aliases.
Here's the bug in malli that Typed Clojure found: https://github.com/metosin/malli/pull/690 The type for the new helper:
(t/ann miu/-reduce-kv-valid (t/All [a k v]
[[a k v -> (t/U (t/Reduced a) a Invalid)] a (t/Option (t/Associative k v)) -> (t/U a Invalid)]))Annotate it myself.
There is no global inference in Typed Clojure.
Did you have to annotate it yourself or did inference catch it?