I've been wanting a better way to define system interfaces at work and I came up with the start of an idea last night. I spent some time experimenting and produced this: https://github.com/julienvincent/malt. The basic idea is to allow defining a more concrete, typed interface from which implementations can be derived. I wanted to attach type information to the interface in a way that doesn't decay (like docs and comments) and that can participate at runtime to do things like coersion, validation, and generation. I'd love some feedback from people to see if this resonates with anyone, or if anyone knows of some prior work in this space. I know of plumatic schema supporting typed protocols but nothing beyond that. There is a note in the repo, but just to reiterate: I wouldn't recommend reading the source code. It was generated by AI. I defined the interface and desired behaviour, from which the macros and clj-kondo hooks were generated. I'll rewrite it myself if it proves to be a fruitful idea
really neat, reminds me of how Prismatic Schema's extension of defrecord was done
Good point for defrecord, I expanded it to support defrecord as well!
:refer-clojure :exclude [def] is basically a no-op, right?
https://github.com/clojure/spec.alpha/blob/eaae63904808a0988f6723d1e9e1ee7db6f07ee5/src/main/clojure/clojure/spec/alpha.clj#L17C3-L17C67
user=> (ns foo (:refer-clojure :exclude [def]))
nil
foo=> (def x 1)
#'foo/x
foo=> (ns bar)
nil
bar=> (defmacro def [])
#'bar/def
bar=> (def x 1)
#'bar/xThere is no def in clojure.core.
> #'clojure.core/def
Unable to resolve var: clojure.core/def in this contextdef exists before clojure.core, https://github.com/clojure/clojure/blob/e43644847d03e6a27a28f99f1d7699da63f1069e/src/clj/clojure/core.clj#L13
this is just a consequence that special forms cannot be shadowed in first position? (invoke position?)
I know all that, I just wonder why def is in :exclude
I think I did a thread on this a bit ago that that is unchecked. You can put anything in there
yeah, you can put anything there, that's why I have an open clj-kondo issue to check of the var really exists. but since there is a special form in there, I wondered if there was any reason for it
https://clojurians.slack.com/archives/CHY97NXE2/p1766226201694829
the only reason I can think of is for some linter warning about redefs (even if it's not true). maybe cursive would have complained at the time?
maybe clj-kondo back in the day
no, clj-kondo never complained about this (and spec was already written before it even existed)
til
:exclude being unchecked feels like a bug to me
not sure if I would call it a bug, but at least it keeps me off the streets and something to add to clj-kondo, so I don't complain
My measly Clojurists Together monthly donation is going to good then 🙌🏻
@jeaye this is odd enough behavior that I'm tagging you for jank out of curiosity for how it handles this. Also makes me wonder if we should test stuff like this in clojure-test-suite as well
It's important for :exclude to be unchecked so that you can write code that works on old and new versions of clojure:
(ns foo (:refer-clojure :exclude [;; added in 1.11
update-vals]))@emma.audrey.g jank's output from the same session inputs.
❯ jank repl
user=> (ns foo (:refer-clojure :exclude [def]))
nil
foo=> (def x 1)
#'foo/x
foo=> (ns bar)
nil
bar=> (defmacro def [])
#'bar/def
bar=> (def x 1)
#'bar/x
So, same behavior as Clojure, if I understand correctly.