Fork me on GitHub

What's people takes on shadowing global vars with local ones? Like say calling a local binding str ?


don’t do it


been bitten more times than i can count by naming things type and then messing up a reference somewhere in the file


I only shadow when I intentionally want to make a var unavailable

Alex Miller (Clojure team)02:12:41

Perfectly fine, I do it all the time

😎 6

(e.g (fn [a] (let [a (normalize a)] …)) )

👍 3

And I assume here you didn't want to rebind a to the normalized a ?


I don’t want to allow access to un-normalized a


i.e. i don’t want to allow access to what came into the fn


Oh ok, this was an example of when you want to explicitly shadow I see


Haha, so I guess its a controversial issue 😛 I'm in the camp of it being totally fine as well. I've never really gotten confused by it, though I guess it would be confusing if it binds to a function. Like a function that took an arg called str which also happened to be a function, that be confusing. But I've never done that.


It's bitten me once or twice but I still do it. There are just too many nice, short, useful names in clojure.core to avoid them all for local bindings.

☝️ 6
truestory 3

type and name are probably the two most common global names that I shadow @didibus -- I have str as an alias for clojure.string but I've never found a need for it as a local symbol. A generic string might just as well be s 🙂


(it would be interesting to scan the codebase to see what else we shadow... is that something clj-kondo can detect @borkdude? I suspect it is... but off by default?)


Currently there is a bug in the linter in that it only works when you use either :include or :exclude certain symbols, but not without those options. This has been fixed on master.


I will release probably soon, but when using either of these options, the linter should work. The default level is :off. See


It seems to be at least partially working already in the extension for VS Code, based on my brief experiments last night.


When you use either :include or :exclude it will work as expected


Even that I'm not sure of now. There was a pretty stupid bug. Let me just roll a release.


I remember him asking about this recently. It might be recently added or abandoned based on feedback


I’ve been bitten by name a few times. I get nervous each time I use it as a var


:shadowed-var -- off by default. Just looked it up.


Maybe I'll turn it on at work and see what we get 🙂


at some point, the number of experts who have been bitten by it says all you need to say


probably 🙂


t and n are fine for type and name, imo


I realized you can freely mix vars and namespace, so even when I alias clojure.string as str its still fine to do: (fn [str] (str/upper-case str))


Even clojure code uses s for strings


extremely common abbreviation


*clojure core


But I alias clojure.spec.alpha to s 😛


alias/var names don’t overlap


never had a single issue with that 🙂


(because it’s impossible)


Anyway, I was just using it as an example. The example that prompted me to ask was we have a thing called Agent in our app, and so the bindings are often (defn [agent ...] ...) and our team were discussing not shadowing the core agent function. So maybe that's a better example?


Heh. I never use agents so shadow away. There’s basically no ambiguity for me :)


Yes, clj-kondo has a linter for that. I fixed an issue with it on master last weekend


Humdum, trying to remember the name of a tracing debug library for Clojure that came about recently (not sayid), but my memory fails me

flowthing08:12:56 was announced pretty recently, at least.

❤️ 3

ah that was it, thank you for aiding my fading memory! 🙂


hi, I have a quick question: I have this list of strings that are all numeric. Before I process it, I map over the list to get numeric values: (map (Integer/parseInt %) my-list) I compile it with no complaint. However, when I run the code, the first time I run it I get a number format exception for the value of "2622048027". When I run it the second time without changing code or recompiling or anything, the code works fine. I understand that Integer/parseInt is supposed to give number format exception. What I do not understand though is why it works the second time I run the code. Anyone has any idea what is happening here?


you forgot # in front of (Integer/parseInt %) is this lambda inside of another anonymous function declaration?


no, I just didn't put it as it triggers slack features


what in the code is: (def in (map hash(Integer/parseInt %) my-list))

Alex Miller (Clojure team)14:12:21

map is lazy so if you're not using all of the result, you won't actually do the parsing


@alexmiller I get that, but what is getting "2622048027" to be a number the second time I run the code?


the first time I need that value, map is evaluated, and that is when (Integer/parseInt "2622048027") is called, and it gives the exception. The second time I run the code, Integer/parseInt has already been called, so it is not called... buut what got "2622048027" into 2622048027?

Alex Miller (Clojure team)14:12:41

I think that number is too big to be an Integer

Alex Miller (Clojure team)14:12:54

Integer/MAX_VALUE is 2147483647

Alex Miller (Clojure team)14:12:24

in general, I almost always use Long/parseLong (because that's the default integer size in Clojure)


it is, and I understand why Integer/parseInt must throw an exception. But I do not understand how it is turning into a number in spite of the eception being thrown

Alex Miller (Clojure team)14:12:47

can you share the actual code?

Alex Miller (Clojure team)14:12:01

from your description, doesn't make sense so must be missing something


yes sure. the code is my solutions to advent of code. I am giving url directly to day 9 solution


I get not found on that link. Might be on my end.


oh, I think I have my repo private for aoc 020


just a second


@U0CMVHBL2 @alexmiller I just made my repo public, please try again

Alex Miller (Clojure team)15:12:38

well, in is lazy so you could use it for a while before discovering an issue


@alexmiller I am not sure that explains why it works the second time I run the code, why is that string turning into a number the second time I run the code?!?!


that does explain why I get a problem after having read many values from in, not immediately, but not why it succeeds the second time...

Alex Miller (Clojure team)15:12:30

stepping away for a meeting


👍 thanks for your time


I can try to evaluate (count in) and the first time it throws an exception, but the second time it returns 608 with no exception.


If I change Integer/parseInt to Long/parseLong and do (count in), I get 1000.


So I would not say it is "working" when it returns 608, except to say it is returning the 608 elements out of the 1000 before the exception occurred.


lazy sequences do cache their results when realizing elements, i.e. they actually allocate memory for elements of the lazy sequence as it is being realized. I suspect when it is realizing it the first time, it is creating the first 608 elements, getting the exception on the 609th, and then leaving the lazy sequence in a state where after 608 elements that is a normal end of the list, rather than a "try to realize this next thing" the way it was when the exception occurrred.

Alex Miller (Clojure team)15:12:34

in cases like this, all bets are off - we don't try to protect you from "broken" lazy seqs


you guys are right, as measured against the expectation that (count in) should be 1000, it is not working. as measured against the expectation of giving an answer to second part of the puzzle... it does produce the correct answer. I need to think further why it gets to evaluating "2622048027" before finding an answer to the puzzle in the first run


I think I got it


or maybe not.. hmm


I guess (partition ... is ran against the 608 elements the second time, and the correct answer to the puzzle is producible with those 608 elements. yeah, I think that is


if you fetch the code and want to reproduce the bug, just run (solution-second-part) twice after compiling the code


This is surprising:

(case (int -1)
  -1 true
  nil false)
Execution error (IllegalArgumentException) at .../eval21818 (form-init2370325502731369149.clj:398).
No matching clause: -1
(case (int -1)
  -1 true
  -2 false)

Alex Miller (Clojure team)15:12:19

that is a bug and we have a ticket for it

Alex Miller (Clojure team)15:12:35

well, maybe it's not the same thing - you might be seeing mismatch between int and long too?

Alex Miller (Clojure team)15:12:57

nah, it's probably the same thing as that bug


Yeah, this works:

(case (int 1)
  1 true
  nil false)


What's the best way to synchronize a function in Clojure? For all its callers?

Alex Miller (Clojure team)22:12:15

locking is the canonical answer

Alex Miller (Clojure team)22:12:00

functions are not synchronized in Clojure, but you can add that semantic inside the function if you really need to

Alex Miller (Clojure team)22:12:18

(but I'd try hard to not need to :)


locking lets you use the low level object monitors that synchronized blocks and methods in java use, but you also have access to


What's the best thing to lock on if using Locking?


Can I lock on the function itself?

Alex Miller (Clojure team)23:12:19

common case is to def/let an (Object.) to act as the lock


Would this be considered weird:

(let [o (Object.)]
  (defn ...
    (locking o ...)))

Linus Ericsson21:12:49

no, that looks ok

Alex Miller (Clojure team)23:12:12

no, but I'd put that around the defn


Sorry, updated it, pressed enter instead of shift+enter first time around

Alex Miller (Clojure team)23:12:53

np, that is a pattern for sure

✔️ 3