Fork me on GitHub
#clj-kondo
<
2022-03-31
>
Ben Sless05:03:32

Is it possible to use kondo for side effect linting / analysis? For example require a function should be pure then get a lint error if this assumption is violated, or query a function if it has side effects?

lassemaatta05:03:30

I'm curious; how would/could you detect if a function has side-effects? By manually adding some explicit metadata or something like that to "color" the functions?

Ben Sless05:03:26

Initially, yes. I think if you default to "all interop is impure unless explicitly stated" and propagate this upwards you'll be 95% there

Ben Sless05:03:30

Even all printing ends up with .append and flush

lassemaatta05:03:04

ah, ok. I think this is one of those questions where that last 5% contains all sorts of nasty edge-cases. A silly function like (defn foo [*a] (swap! *a inc) sure looks quite side-effecting in isolation, but perhaps it's (sometimes) invoked from (defn bar [val] (let [*a (atom val)] (foo *a) @*a)) etc 🙂 or in case of printing your function might be wrapped in with-out-str

Ben Sless06:03:18

That's where you do "fun" things like life-time analysis

Ben Sless06:03:45

Isn't it similar to the go block analyzer marking transitions?

borkdude10:03:17

@UK0810AQ2 Could work to a certain degree, but what kind of input/output would you expect? Need more specific examples.

Joshua Suskalo18:03:24

I think that "all interop is impure" would be pretty troublesome in a lot of codebases considering you'd have to, for one, manually examine most of clojure core for this since so much of it delegates to clojure.lang.RT, and then a lot of very common data structure libraries like sorted maps etc. would then have to get custom linting as well considering their authors are unlikely to package clj-kondo configs. Not saying it's impossible by any stretch to start from there, but it definitely feels like it would require a lot of community effort.

Ben Sless05:04:54

@U04V15CAJ I think there are linters you can build on top of this analysis. Few ideas: Maximum recommended depth for side effects Maximum number of side effects in function call Assertions - specify a certain function must remain pure, then down the line trip that linter if something violated this assumption

sheluchin13:03:58

Should there be a warning for something like this?

(defn foo
  ([x & {:keys [y]
         :or {y false}}]
   (foo x y))
  ([x y]
   [x y]))
Looks like clj-kondo has no problem with it, but Clojure gives:
Syntax error compiling fn* ...
Can't have fixed arity function with more params than variadic function

borkdude13:03:02

yes, clj-kondo should lint this. there might be an issue but if not, feel free to create it

lread15:03:01

I just muddled through how to configure clj-kondo to ignore an assert expr brought in by https://github.com/nubank/matcher-combinators. In the end it was an easy :unresolved-symbol {:exclude [(clojure.test/is [match?])]} in my clj-kondo config. Might be worth me adding a tip under https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#unresolved-symbol docs?

borkdude15:03:37

isn't that already in there?

lread15:03:33

Maybe, but not as an explicit example for test assert expressions.

borkdude15:03:04

{:linters
  {:unresolved-symbol
    {:exclude [(riemann.streams/streams [where])]}}}
is a similar example?

borkdude15:03:22

oh yes, I think adding the clojure.test example is much better and more common. PR welcome

borkdude15:03:39

we can replace the existing example

lread15:03:12

Ok, will do.