clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
2020-12-09T02:48:35.222300Z

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

2020-12-09T02:49:54.222500Z

donโ€™t do it

2020-12-09T02:50:36.223200Z

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

2020-12-09T02:51:22.223900Z

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

alexmiller 2020-12-09T02:51:41.224800Z

Perfectly fine, I do it all the time

๐Ÿ˜Ž 2
โœ… 3
2020-12-09T02:51:51.225100Z

(e.g (fn [a] (let [a (normalize a)] โ€ฆ)) )

๐Ÿ‘ 1
2020-12-09T03:00:40.226700Z

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

2020-12-09T03:01:32.227400Z

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.

seancorfield 2020-12-09T03:27:51.228300Z

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.

โ˜๏ธ 2
1
seancorfield 2020-12-09T03:33:56.229700Z

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 ๐Ÿ™‚

seancorfield 2020-12-09T03:37:04.230600Z

(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?)

borkdude 2020-12-09T10:20:19.246700Z

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.

borkdude 2020-12-09T10:21:30.246900Z

I will release probably soon, but when using either of these options, the linter should work. The default level is :off. See https://github.com/borkdude/clj-kondo/blob/master/doc/linters.md#shadowed-var

seancorfield 2020-12-09T19:43:47.269800Z

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

borkdude 2020-12-09T19:44:29.270Z

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

borkdude 2020-12-09T19:46:59.270200Z

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

dpsutton 2020-12-09T03:37:32.231300Z

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

dpsutton 2020-12-09T03:37:57.232Z

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

seancorfield 2020-12-09T03:43:11.232400Z

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

seancorfield 2020-12-09T03:43:24.232700Z

Maybe I'll turn it on at work and see what we get ๐Ÿ™‚

2020-12-09T03:44:09.233Z

I donโ€™t want to allow access to un-normalized a

2020-12-09T03:44:20.233400Z

i.e. i donโ€™t want to allow access to what came into the fn

2020-12-09T03:45:02.234600Z

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

2020-12-09T03:45:05.234900Z

probably ๐Ÿ™‚

2020-12-09T03:45:21.235600Z

t and n are fine for type and name, imo

2020-12-09T03:45:30.235800Z

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))

2020-12-09T03:46:02.236500Z

Even clojure code uses s for strings

2020-12-09T03:46:12.236800Z

extremely common abbreviation

2020-12-09T03:46:28.237200Z

*clojure core

2020-12-09T03:46:54.237600Z

But I alias clojure.spec.alpha to s ๐Ÿ˜›

2020-12-09T03:47:32.238400Z

alias/var names donโ€™t overlap

2020-12-09T03:47:38.238700Z

never had a single issue with that ๐Ÿ™‚

2020-12-09T03:48:06.239700Z

(because itโ€™s impossible)

2020-12-09T03:48:22.240100Z

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?

dpsutton 2020-12-09T03:52:30.242100Z

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

2020-12-09T04:23:26.242500Z

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

borkdude 2020-12-09T07:58:29.244200Z

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

viesti 2020-12-09T08:49:03.245800Z

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

flowthing 2020-12-09T08:50:56.245900Z

https://github.com/jpmonettas/flow-storm was announced pretty recently, at least.

โค๏ธ 1
viesti 2020-12-09T08:51:48.246200Z

ah that was it, thank you for aiding my fading memory! ๐Ÿ™‚

bibiki 2020-12-09T14:44:27.255500Z

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?

2020-12-09T14:46:49.255600Z

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

bibiki 2020-12-09T14:47:19.256200Z

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

alexmiller 2020-12-09T14:47:21.256400Z

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

bibiki 2020-12-09T14:48:01.256500Z

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

bibiki 2020-12-09T14:49:19.257200Z

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

bibiki 2020-12-09T14:51:14.258600Z

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?

alexmiller 2020-12-09T14:51:41.258900Z

I think that number is too big to be an Integer

alexmiller 2020-12-09T14:51:54.259200Z

Integer/MAX_VALUE is 2147483647

alexmiller 2020-12-09T14:52:24.260200Z

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

bibiki 2020-12-09T14:52:32.260400Z

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

alexmiller 2020-12-09T14:52:47.260700Z

can you share the actual code?

alexmiller 2020-12-09T14:53:01.261Z

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

bibiki 2020-12-09T14:53:44.261500Z

yes sure. the code is my solutions to advent of code. I am giving url directly to day 9 solution https://github.com/bibiki/aoc-2020/blob/main/src/aoc_2020/day_9/solution.clj

bibiki 2020-12-09T14:55:16.262300Z

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

2020-12-09T14:55:36.262400Z

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

bibiki 2020-12-09T14:56:32.262600Z

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

bibiki 2020-12-09T14:56:35.262800Z

just a second

bibiki 2020-12-09T14:58:51.263Z

@andy.fingerhut @alexmiller I just made my repo public, please try again

alexmiller 2020-12-09T15:00:38.263200Z

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

bibiki 2020-12-09T15:01:41.263400Z

@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?!?!

bibiki 2020-12-09T15:02:45.263600Z

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...

alexmiller 2020-12-09T15:03:30.263800Z

stepping away for a meeting

bibiki 2020-12-09T15:03:44.264Z

๐Ÿ‘ thanks for your time

2020-12-09T15:06:02.264700Z

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.

2020-12-09T15:06:24.264900Z

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

2020-12-09T15:06:49.265100Z

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.

jumar 2020-12-09T15:07:42.265400Z

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)
true

2020-12-09T15:08:47.265500Z

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.

alexmiller 2020-12-09T15:09:34.265700Z

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

bibiki 2020-12-09T15:11:19.266100Z

hmmm

alexmiller 2020-12-09T15:11:19.266300Z

that is a bug and we have a ticket for it

alexmiller 2020-12-09T15:12:02.266600Z

https://clojure.atlassian.net/browse/CLJ-2275

alexmiller 2020-12-09T15:12:35.267Z

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

bibiki 2020-12-09T15:13:45.267200Z

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

alexmiller 2020-12-09T15:13:57.267600Z

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

bibiki 2020-12-09T15:14:25.267700Z

I think I got it

bibiki 2020-12-09T15:14:33.268Z

or maybe not.. hmm

jumar 2020-12-09T15:14:33.268200Z

Yeah, this works:

(case (int 1)
  1 true
  nil false)
true
Thanks!

bibiki 2020-12-09T15:16:38.268300Z

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

bibiki 2020-12-09T15:17:06.268500Z

thanks @alexmiller @andy.fingerhut

2020-12-09T22:31:45.271600Z

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

alexmiller 2020-12-09T22:36:15.271900Z

locking is the canonical answer

alexmiller 2020-12-09T22:37:00.273100Z

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

alexmiller 2020-12-09T22:37:18.273400Z

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

2020-12-09T22:54:20.274800Z

locking lets you use the low level object monitors that synchronized blocks and methods in java use, but you also have access to https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/package-summary.html

2020-12-09T23:19:06.275600Z

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

2020-12-09T23:19:17.275800Z

Can I lock on the function itself?

alexmiller 2020-12-09T23:19:52.276Z

I wouldn't

alexmiller 2020-12-09T23:20:19.276600Z

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

2020-12-09T23:21:00.277700Z

Would this be considered weird:

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

Linus Ericsson 2020-12-21T21:16:49.296300Z

no, that looks ok

alexmiller 2020-12-09T23:21:12.278100Z

no, but I'd put that around the defn

alexmiller 2020-12-09T23:21:18.278400Z

not in the defn

alexmiller 2020-12-09T23:21:24.278600Z

yeah, have done

2020-12-09T23:21:39.279Z

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

alexmiller 2020-12-09T23:21:53.279300Z

np, that is a pattern for sure

โœ”๏ธ 1