This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-02-13
Channels
- # announcements (18)
- # babashka (52)
- # beginners (47)
- # calva (45)
- # clj-kondo (31)
- # clojure (18)
- # clojure-brasil (2)
- # clojure-europe (3)
- # clojure-sweden (25)
- # clojurescript (19)
- # cursive (15)
- # datalevin (11)
- # defnpodcast (2)
- # duct (1)
- # editors (1)
- # emacs (6)
- # gratitude (1)
- # introduce-yourself (6)
- # jobs-discuss (11)
- # leiningen (3)
- # lsp (10)
- # luminus (2)
- # off-topic (4)
- # podcasts-discuss (2)
- # reitit (2)
- # shadow-cljs (10)
- # sql (9)
- # xtdb (4)
how to understand function http://clojure.core.cat
If you have a list of lists, cat can give you a list. It's a transducer, meaning you can use it with different sequence types using into. Lists, vectors, maps, sets.
Perhaps the examples here make sense to you? https://clojuredocs.org/clojure.core/cat
I haven't used it much in practice, perhaps others should chime in too. In case I'm missing / misunderstanding something.
I'm trying to understand a little puzzle
user=> ([2 5 9] 4294967296)
2
user=> ([2 5 9] 4294967297)
5
user=> ([2 5 9] 4294967299)
Execution error (IndexOutOfBoundsException) at user/eval461 (REPL:1).
null
Looks like 2^32 triggers some funny behavior with vector indices, what's going on under the hoods?! Why does it sort of "rolls over" and ([2 5 9] 4294967296)
behaves like ([2 5 9] 0)
?When you use a vector like this, you’re calling the invoke
method on clojure.lang.APersistentVector
. This checks if the argument provided is an “integer”, which checks of the data type is one of Integer
, Long
, BigInt
or BigInteger
. Your number is a long
, which gets boxed into a Long
, so the answer is true
.
At this point, the value is cast to a java.lang.Number
and .intValue()
is called on it. This truncates to only the bottom 32 bits
You can see this at: https://github.com/clojure/clojure/blob/84811650bb33846c7212f391468f9661819b906b/src/jvm/clojure/lang/APersistentVector.java#L295
You can see it in Java (using jshell):
jshell> ((Number)4294967297L).intValue()
$26 ==> 1
It doesn’t matter what the top bits are, they will be truncated:
jshell> 0xFFFFFFFF00000001L
$32 ==> -4294967295
jshell> ((Number)(-4294967295L)).intValue()
$33 ==> 1
Thanks! I had just started looking into the implementation of PersistentVector, https://github.com/clojure/clojure/blob/38bafca9e76cd6625d8dce5fb6d16b87845c8b9d/src/jvm/clojure/lang/APersistentVector.java#L291 ❤️
Wondering if this truncation could lead to bugs in practice, @U051N6TTC do you have any insight on to why truncate vs throw an exception in this case?
This sort of thing shows up a bit since Clojure tries to use long
values exclusively, but Java defaults to int
in many places (such as array offsets). Clojure’s implementation is done in Java, which is where it shows up.
There have been bugs, but they’re relatively rare
Hmm that implementation decision also does mean that vectors are limited to a 32bit index space, right?
I wasn’t sure, so I just checked… https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Vector.html also indexes by int
When Java was first released there really weren’t any 64 bit CPUs in use. When Java moved to 64 bit systems it was able to update to the new address space (meaning that individual processes could access more than 2GB) but the specification of Java didn’t change, and it continued to use 32 bit integers for things like arrays
I'm not too familiar with Java, coming more recently from Go where arrays are 64bit on 64bit OS arch
Yes, it’s a bit annoying. I’ve often worked with multi-gigabyte files that get memory mapped. To do this you need to create an array of maps. It works, but it’s a frustrating nuisance
I suspect the main reason for the silent truncation vs. exception is performance reasons. While it could cause bugs in some cases, note that it shouldn't cause bugs in at least one common case where you are traversing through consecutive indexes.
In Clojure, traversal through consecutive indexes is likely to be performed via the seq
api. Indexing is likely to be via nth
.
Generally, nth
will be called when the code has identified which offset to request, else it runs the risk of IndexOutOfBoundsException
.
As for checking for the range of the input (as opposed to the bounds check), it is only required for some types, and it’s checking for an index where you are unlikely to ever exceed. Sure, there’s an argument against the consistency of behavior here, but it’s not likely to be a practical concern
is there some blog post about what Date class to use? java.time.Instant vs java.util.Date ? My current use case is to say "UtcNow" and "UtcNow" 5 minutes ago in ms.
:startTime
(.toEpochMilli
(.minusSeconds
(java.time.Instant/now)
(* 60 5)))
:endTime
(.toEpochMilli
(java.time.Instant/now))
Just agreeing on your judgement - because it seems to be a mutable object and we know what Rich Hickey has to say about that it's just bad
Oh yes, I see what you mean now. Yes, although that's just one of the problems with java.util.Date
(see e.g. https://stackoverflow.com/questions/1969442/whats-wrong-with-java-date-time-api).
cognitect.aws (:GetItem (aws/ops dynamodb)) =>
{:name "GetItem",
...
:request
{:TableName string,
:Key [:map-of string shape/AttributeValue],
...}
:refs
#:shape{AttributeValue
{:L [:seq-of shape/AttributeValue],
:M [:map-of string shape/AttributeValue],
:NS [:seq-of string],
...}}}
what is the nature of :refs
?
just this :
#:foo{'fa {}}
?https://clojure.org/reference/reader#_maps see under "Map namespace syntax".
You can do (set! *print-namespace-maps* false)
to print it the "regular" way (i.e. {:shape/AttributeValue ,,,}
) if you prefer.
Workflow efficiency question for users of VSCode (& Calva): As I'm typing something like a function definition and my cursor is inside a set of brackets or quotes (the last one was inserted by paredit, I guess) is there a way to move to the next line, jumping out of the brackets/quotes at the same time? I'm trying to avoid having to hit Right Arrow + Enter every time.
The good folks over at #calva will probably be able to give you a better answer, but I think what you're looking for is the "Forward Up Sexp" ParEdit command (https://calva.io/paredit/) followed by a newline (that's kind of the other way around, though, but the end result is the same). I don't know whether you can configure a key binding to run more than one editor command at once in VS Code, though. Maybe there's a plugin for that?
Ah, thank you 🙏:skin-tone-3: I will look into the key binding idea and see if I can map something like Shift+Enter to do it.