I’d like to announce a preview-quality alpha release of Guardrails Analyzer! This is a code analysis tool I’ve been tinkering with since 2020, and the advent of LLMs finally made it easy for me to do a refactoring fix that I needed but hadn’t had time to do. The tool is a runtime analyzer that is somewhere between clj-kondo and formal types for Clojure. It leverages specs (Clojure Spec, Malli coming soon) to do data flow analysis of functions in order to find potential problems. This goes far beyond the capabilities of simple static analysis, and lands you in a new land of “A lot of the power of types, plus the power of data flow analysis, but without the constraints of types). The result is missing some of the niceties of types (e.g. compile fails when you do something completely insane), but it has the added advantage of finding really interesting fine-grained problems that type systems and other static analysis can’t hope to see. The main repository is at https://github.com/fulcrologic/guardrails-analyzer, and here’s the IntelliJ plugin (https://github.com/fulcrologic/guardrails-intellij-plugin/releases/tag/1.0.0-alpha). The system includes an LSP server, and I’ve played with making it work via LSP with at least vim, so hopefully it won’t be hard to integrate with whatever editing environment you have. I’m still working on the documentation and workflow, but you can at least see a preview demo here: https://youtu.be/0uxkMPh9XaU
Ah fantastic. I've been playing around with similar ideas but haven't had time to do a full project. Very happy someone found the value here. @tony.kay Are you doing compile time analysis within forms bounded by the syntax that does actual runtime checks?
For example, the compile time check encounters a form that's a runtime check (e.g. a Malli validate call) and, assuming that check passes, can now assume what the current data shape can be?
There is no compile. I'm literally interpreting the code, and using generators and data flow analysis to look for possible problems. The checker runs within your env so it can use whatever specs and generators you've defined.
Okay I'll have to take a closer look. Sorry when I said "compile" what I meant was "compile time" which means you only have access to the source code state, not runtime state.
Congrats on finally releasing this :)
Yeah thanks. We talked about it a Loooooong time ago. At least now you can see what I was talking about 😄
This is very cool 😎
Hi clojure community!
I'm sharing here https://github.com/semantic-namespace/contract, a semantic approach to clojure.core/def partially based on clojure.core.spec/def
This library embraces the https://clojure.org/about/spec#_prior_arthttps://clojure.org/about/spec#_prior_art to help on the highlighted parts of following clojure.spec guidelines "expressivity > proof" paragraph (copy pasted from https://clojure.org/about/spec#_expressivity_proof)
> Guidelines
> ...
> https://clojure.org/about/spec#_expressivity_proof proof>
> There is no reason to limit our specifications to what we can prove, yet that is primarily what type systems do. There is so much more we want to communicate and verify about our systems. This goes beyond structural/representational types and tagging to predicates that e.g. narrow domains or detail relationships between inputs or between inputs and output. Additionally, the properties we care most about are often those of the runtime values, not some static notion. Thus spec is not a type system.
more details on https://tangrammer.codeberg.page/on-the-clojure-move/output/posts/semantic-namespace-contract.html
Would love to hear your thoughts!
PS: also created a hacker news link https://news.ycombinator.com/item?id=45618221
You might want to post this to the #rdf channel.
Hi @alexmiller I thought that if anyone was interested they could go into articles and repos created 😅 anyway I'll try to add more specific details here about > There is so much more we want to communicate and verify about our systems To allow systems to communicate about themselves, they need introspection support. Clojure offers different helpers depending the type of thing we want to query about: for vars & funs defined (meta) , for namespaces and ns mappings (ns-public, ns-map, ns-interns ...), for protocols (extenders, satisfies? ...), for defrecords (bases, supers), for multimethods (methods, get-method ) and for hierarchies (isa?, ancestors, descendants, parents). Each of these parts live separately and are not unified (data returned differs if var, function, namespace, protocol, record .. ) thus we can't answer basic system questions.... "Find all functions that take email as input" "GDPR audit: Which functions process email without encryption?" "Security review: What endpoints expose email without auth?" "Refactoring: Who still uses deprecated email-v1 spec?" "What breaks if I change user spec?" "Which endpoints expose PII without authentication?" "Find all functions storing user data without retention policies" https://github.com/semantic-namespace/contract lib addresses this gap by providing: - Unified RDF triple store - Cross-cutting semantic queries - Context-dependent relationships - Everything as queryable data Essentially builds a semantic layer on top of Clojure's var system, making the implicit relationships explicit and queryable as RDF triples. leaving here another example using endpoint as domain problem https://github.com/semantic-namespace/contract/blob/main/dev/src/semantic_namespace/endpoint_example.clj hope this new comment helps on clarifying the direction and purpose I'm trying to share
I am well-primed to be interested in this but even after seeing your talk and reading the announcement twice, I'm still unclear what problem you're trying to solve or what you are proposing to solve it. I generally understand and agree with the ideas outlined, just not sure what you're driving towards.
https://github.com/igrishaev/pg2 is out (it's a client for Postgres). Tiny performance tweaks here and there, all together they make queries about 25% faster. E.g.: 650ms -> 500ms on one machine, 511ms -> 408ms on another machine (measured with Criterium + local DB).