This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-03-28
Channels
- # aleph (16)
- # announcements (7)
- # asami (4)
- # aws (26)
- # babashka (26)
- # babashka-sci-dev (50)
- # beginners (118)
- # biff (7)
- # calva (15)
- # cider (6)
- # clj-kondo (8)
- # cljs-experience (3)
- # clojure (30)
- # clojure-austin (26)
- # clojure-europe (20)
- # clojure-france (2)
- # clojure-ireland (1)
- # clojure-nl (3)
- # clojure-norway (2)
- # clojure-spec (7)
- # clojure-uk (6)
- # clojurescript (12)
- # community-development (5)
- # conjure (1)
- # copenhagen-clojurians (3)
- # core-typed (71)
- # cursive (3)
- # datomic (1)
- # emacs (4)
- # fulcro (2)
- # helix (2)
- # introduce-yourself (3)
- # jobs (1)
- # london-clojurians (6)
- # lsp (122)
- # malli (2)
- # missionary (5)
- # overtone (14)
- # pathom (4)
- # polylith (1)
- # reagent (4)
- # reitit (1)
- # releases (1)
- # shadow-cljs (80)
- # testing (10)
- # tools-deps (6)
- # vim (3)
- # xtdb (19)
(ns tyt
(:require
[typed.clojure :as t]
[malli.core :as m]))
(m/=> foo [:=> [:cat :int] :int])
(defn foo [t]
"abc")
(comment
(t/check-ns-clj))
Going through the malli example, first time in a long time trying to use typed clojure. Can't seem to get it to break. Am I doing something wrong?
(or rather, it doesn't fail unless i restart the repl and vice versa when changing the return from "ABC" to 3)
Hmm, so check-ns-clj fails with (defn foo [t] "abc")
, but only after restarting the REPL?
mashing cmd + S does seem to make it work. Intellij saves when you switch tabs or give it that hint
yes i did. usually with IntelliJ I am not actively thinking about when the files are saved because they "just are"
by loading the namespace in the REPL, you've evaluated m/=>
. so t/check-ns-clj
just retrieves it from malli.
Type checking works much like evaluation. except it's read -> macroexpand/type check -> eval
for each form, left to right.
Here's what happens:
1. you create the tyt
namespace.
2. you call t/check-ns-clj
3. now, the type checker basically calls (require 'tyt :reload)
, except just before evaluating each form, the form is type checked.
so (check-form '(m/=> ..))
is called before (check-form '(defn foo ..))
, so the malli schema is registered just in time.
ah, so what's happening there is that if there's no expected type available, it will check as [Any -> Any]
. and it succeeds.
clj-kondo is very different, and I don't know if it's possible to combine the two. Typed Clojure relies on being able to really macroexpand your code, which is exactly what clj-kondo cannot.
Interestingly, clj-kondo and Typed Clojure are converging in other ways, since we're both making extensible rules for macros that we don't recognize. So maybe, Typed Clojure will know so many macros eventually that we can think of a graalvm offline version. But, I still don't really understand why you'd want that over importing a jar.
The flexibility you get is perfectly demonstrated by the malli integration you're playing with. You'd need extra steps to export the malli to a clj-kondo config to do this.
most of the motivation is (i think) around the editor experience, since requiring a running repl for feedback has been a barrier
I think the folks that make better use of it could make a more convincing pitch though
so "hooks" and the pseudo macro-expansion they provide wouldn't be enough for typed clojure?
IMO clj-kondo is perfect the way it is, I'm just commenting on what you'd lose by making Typed Clojure move to graalvm.
this is the no.1 question I get in the last few years 🙂 but Typed Clojure is 11 years old at this point, it's a totally different ball game on graalvm.
The best I could hope to contribute realistically is maybe help borkdude port some of Typed Clojure's type system features to clj-kondo.
It's about the same complexity as porting eastwood to graalvm. I haven't seen that suggested anywhere, which makes me think there are some misconceptions about Typed Clojure floating around 🙂
(also I am getting the feeling that i'm maybe a few months early since :map isn't supported)
Yes, perhaps, but you trying it out gives me an incentive to finish it so thank you. 🙂
I bet I can knock out a good chunk of support by just copying the malli.clj-kondo namespace.
I would really like to know what the real challenges are in practice (you know, asides from :map not being implemented xD).
I have a feeling we'll need a way to embed malli syntax into Typed Clojure syntax. Say you have a big map defined in malli, and you need to override a type annotation, you'd want to be able to refer to the big malli map without rewriting the whole thing in typed clojure
(def MyMassiveMalliType [:cat ... ...])
(t/ann foo [(Malli MyMassiveMalliType) -> ...])
@emccue I added a few dozen more malli -> type conversions, typed.malli 1.0.24 is currently releasing please check it out when the build finishes.
check-ns-clj sources files in the same way as require
. It just needs to be on the classpath in the normal place.
okay that went pretty quick - it skips checking namespaces that don't depend on clojure.core.typed
so i guess we would add a dummy require to turn it on ns by ns
(->> (all-ns)
(filter #(string/starts-with? (str %) "lumanu"))
(map (comp symbol str))
(t/check-ns-clj))
Yeah that part is in flux. Before, that was important because check-ns
checked all dependencies transitively. This is no longer the case, but the requirement is still there.
Yeah, the workflow is still not obvious to me after all these years. I just do
(deftest type-checking
(is (check-ns-clj '[ns1 ns2 n3])))
I'm really leaning into a single file being the unit of type checking these days. Not a project, or a set of ns dependencies. Mainly for performance reasons.
One of the reasons users stopped using core.typed was that it forced you to check dependencies before doing anything else. Which was an agonizingly long time. This is no longer the case.