good morning
Good morning, fellow Cloj_eu_rians!
goeiemorgen!
good morning, code conjuring folks!
ayup chucks
Mogge
good morninβ
morny-morn!
morning!
Good Morning!
good humane morning
What better excuse for a walk than to pick up a parcel containing my new A whistle ππΆ
Out of curiosity: What's an "A whistle"? "A" like the reference tuning pitch of 440Hz?
I don't know the hertz - tin whistles are an octave or two higher than the reference, I think - but it's tuned to A major, yes π
morning πΆ just got in from a lovely little walk β βΊοΈ
Morning! I'm waiting for the biblical rain here in Manchester to slow a little before starting my walk π§οΈ
looks like it's got to this side of the pennines ... #weather-watch
morning
good morning folks
morning
Morning!
Making some breaking changes
ground breaking!!
That looks fun!
(transient concrete)
(apply concrete)
You opted for abstraction over concretion
Love the puns π should be something about breaking the build(ing) as well, but brain capacity is gone. All good fun, except for carrying the stuff outside.
shame that update-vals / update-keys can't take additional arguments
(update-vals m update-in [:foo :bar] inc)
(swap! a update-vals update-in [:foo :bar] inc)
etcworth an ask.clojure perhaps?
also sharp edge, calling these on a sorted map does not return a sorted map!
(update-vals m #(update-in % [:foo :bar] inc)) doesn't seem much pain, compared to trying to change a core function... π
true, but update etc do support it :)
(seriously tho', it might be interesting to see how widespread update-(vals|keys) with an anonymous fn like that is out in the wild?)
I'm mostly curious if it's been considered. My guess is it's intentional, given that core stuff tends to be thought through very thoroughly, but maybe not. I really love the "uniform update model" or whatever they call it, stacking swap!/update/update-in etc
@seancorfield anecdotaly, I count about 5-6 of these in a ~40k lines codebase
Okay, made me curious about our work codebase: we have 20 calls to update-vals or update-keys across 150k lines. The ones that have anon fns are all more complex than the extra args would support. So this enhancement wouldn't help us π
@borkdude When I searched, this code in taoensso/encore hooks showed up:
(let [{:keys [src alias attrs body]} (hooks/sexpr alias-node)
;; workaround as can't seem to (get) using a token-node
;; and there's no update-keys (yet) in sci apparently
[& {:as node-as-map}] (:children alias-node)
{:keys [attrs body]} (zipmap (map hooks/sexpr (keys node-as-map))
(vals node-as-map))]
(hooks/list-node
[(hooks/token-node 'taoensso.encore/defalias)
(or alias src) (hooks/token-node src) attrs body]))
Is that still true of sci?it is in bb but not in SCI by default since it supports older versions of clojure but maybe I should give up on that and always support the newest
there was a SCI issue about this today
Seems like it could still support older versions of Clojure but have update-keys and update-vals? Or are you concerned about code that defines their own, prior to... 1.11?
I don't intend to copy/paste too many functions, I use most directly from the host clojure
I guess I don't understand enough about sci to understand that comment π
that's basically one giant hash-map with symbols to copied functions from clojure
> also sharp edge, calling these on a sorted map does not return a sorted map! not even update-vals?
user=> (apply sorted-map (range 100))
{0 1, 2 3, 4 5, 6 7, 8 9, 10 11, 12 13, 14 15, 16 17, 18 19, 20 21, 22 23, 24 25, 26 27, 28 29, 30 31, 32 33, 34 35, 36 37, 38 39, 40 41, 42 43, 44 45, 46 47, 48 49, 50 51, 52 53, 54 55, 56 57, 58 59, 60 61, 62 63, 64 65, 66 67, 68 69, 70 71, 72 73, 74 75, 76 77, 78 79, 80 81, 82 83, 84 85, 86 87, 88 89, 90 91, 92 93, 94 95, 96 97, 98 99}
user=> (update-vals *1 inc)
{0 2, 70 72, 62 64, 74 76, 86 88, 20 22, 72 74, 58 60, 60 62, 24 26, 88 90, 46 48, 4 6, 54 56, 92 94, 48 50, 50 52, 32 34, 40 42, 56 58, 22 24, 90 92, 36 38, 44 46, 6 8, 28 30, 64 66, 34 36, 12 14, 2 4, 66 68, 82 84, 76 78, 68 70, 14 16, 78 80, 26 28, 16 18, 38 40, 98 100, 30 32, 96 98, 10 12, 18 20, 52 54, 42 44, 80 82, 94 96, 8 10, 84 86}
user=> (type *1)
clojure.lang.PersistentHashMap(same with update-keys, which should be no surprise)
Source:
(with-meta
(persistent!
(reduce-kv (fn [acc k v] (assoc! acc k (f v)))
(if (instance? clojure.lang.IEditableCollection m)
(transient m)
(transient {}))
m))
(meta m)))I think {} would need to be (empty m) for that to be retained?
I thought they had used empty in update vals
I recall asking Alex about it years ago
Interesting
Maybe there is no transient sorted map?
What does (into (sorted-map) (range ...)) return
Seems likely:
user=> (apply sorted-map (range 100))
{0 1, 2 3, 4 5, 6 7, 8 9, 10 11, 12 13, 14 15, 16 17, 18 19, 20 21, 22 23, 24 25, 26 27, 28 29, 30 31, 32 33, 34 35, 36 37, 38 39, 40 41, 42 43, 44 45, 46 47, 48 49, 50 51, 52 53, 54 55, 56 57, 58 59, 60 61, 62 63, 64 65, 66 67, 68 69, 70 71, 72 73, 74 75, 76 77, 78 79, 80 81, 82 83, 84 85, 86 87, 88 89, 90 91, 92 93, 94 95, 96 97, 98 99}
user=> (transient *1)
Expected IEditableCollection, but was given PersistentTreeMap, at user/eval18728 (REPL:1) - runtime error (unexpected type).
user=> (apply sorted-map (range 100))
{0 1, 2 3, 4 5, 6 7, 8 9, 10 11, 12 13, 14 15, 16 17, 18 19, 20 21, 22 23, 24 25, 26 27, 28 29, 30 31, 32 33, 34 35, 36 37, 38 39, 40 41, 42 43, 44 45, 46 47, 48 49, 50 51, 52 53, 54 55, 56 57, 58 59, 60 61, 62 63, 64 65, 66 67, 68 69, 70 71, 72 73, 74 75, 76 77, 78 79, 80 81, 82 83, 84 85, 86 87, 88 89, 90 91, 92 93, 94 95, 96 97, 98 99}
user=> (transient (empty *1))
Expected IEditableCollection, but was given PersistentTreeMap, at user/eval18732 (REPL:1) - runtime error (unexpected type).
(error messages courtesy of rephrase π )Not at the computer
Hah
user=> (into (sorted-map) (partitionv 2 (range 50)))
{0 1, 2 3, 4 5, 6 7, 8 9, 10 11, 12 13, 14 15, 16 17, 18 19, 20 21, 22 23, 24 25, 26 27, 28 29, 30 31, 32 33, 34 35, 36 37, 38 39, 40 41, 42 43, 44 45, 46 47, 48 49}
user=> (type *1)
clojure.lang.PersistentTreeMapah hmm
so sorted-map and sorted-set aren't IEditableCollections
Interesting
found my https://clojurians.slack.com/archives/C06MAR553/p1631697606301100?thread_ts=1631652109.282200&cid=C06MAR553, it's only tangentially related as it's about update-keys
The impl of update-keys and update-vals are subtly different: update-keys always uses (transient {}) whereas update-vals will use (transient m) if it is editable.
yeah, that's why it's tangential
but them sorted collections not being editable makes me want to reconsider using them as first args to into vs sorting after into {}
Apparently, we don't use sorted-set or sorted-map anywhere in our code at work...
I made an https://ask.clojure.org/index.php/12107/update-keys-and-update-vals-missing-the-args-from-update?show=12107#q12107 a while back, I think it's not a big deal, but it bugs me a bit that I can't chain them like the other update fns in core. Consider voting for it if you agree π
It also bugs me. However, looking at our codebase of the 5 update-* with anon functions, only 2 would've benefitted from this arity. In @seancorfieldβs codebase apparently it was 0 so I personally don't feel the urgency π«
I voted for the Ask years ago, but I also upvoted Alex's answer about why they are not variadic π
Β―\(γ)/Β―
Please do feel free to add more upvotes on the question in ask or more comments with specific use cases.
Both of those help raise the priority.
sorted-map and sorted-set are great, I've really come to appreciate them on our current project. Together with subseq/rsubseq they become powerful in-memory indexes that you can scan from any point in either direction. Great for time series data for instance and for any kind of range queries. The ones in core don't have transients, there's a library that does have them and is otherwise compatible https://github.com/clojure/data.avl
found this https://ask.clojure.org/index.php/12073/update-vals-not-preserving-sorted-maps
Thanks @plexus, I'm starring that lib
I wonder why core sorted map and set don't support transients though