This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-07-08
Channels
- # aleph (10)
- # announcements (2)
- # babashka (1)
- # beginners (22)
- # biff (5)
- # calva (1)
- # clj-kondo (46)
- # clj-on-windows (7)
- # clojure (88)
- # clojure-denver (12)
- # clojure-europe (41)
- # clojure-losangeles (1)
- # clojure-norway (6)
- # clojurescript (5)
- # conjure (4)
- # fulcro (13)
- # humbleui (1)
- # hyperfiddle (70)
- # jobs (5)
- # juxt (1)
- # meander (12)
- # off-topic (42)
- # practicalli (6)
- # releases (2)
- # shadow-cljs (12)
- # tools-deps (1)
I'm working with nested HashMaps as follows:
(def m (doto (new java.util.HashMap)
(.put :foo (new java.util.HashMap))
(.put :bar (new java.util.HashMap))))
{:foo {}, :bar {}}
Now I want to add a certain key into the nested :foo
map. The code below does the job but triggers a reflection warning:
(-> ^java.util.Map m (.get :foo) (.put :a 1))
m
{:foo {:a 1}, :bar {}}
;; call to method put on java.lang.Object can't be resolved (no such method).
How can I solved it? I tried the double-dot macro, with-meta but none of these worked. Thanks!(let [^java.util.Map inner (.get m :foo)] (.put inner :a 1))
Right, and I was trying
(.. ^java.util.Map m ^java.util.Map (get :foo) (put :a 1))
the code with -> works greatI’d write a utility function jmap-get-in
(defn ^java.util.Map get-submap [^java.util.Map m ks]
(loop [^java.util.Map ret m
[k & more] ks]
(if k
(recur (.get ret k) more)
ret)))
so this makes it possible to return a nested map already marked with the right typehint
obviously this code is super sloppy: nil keys won’t work, and it doesn’t check if map has the key and that the actual return is a map
when using clj
tools with -T
is it possible to get function descriptions/ useage string?
roklenarcic@Roks-MacBook-Pro codescene % clj -Ttools show :tool new
{:lib io.github.seancorfield/deps-new,
:coord
{:git/tag "v0.4.13",
:git/sha "879c4eb50df92fcd8c11423c2081e00998d7b613",
:git/url ""}}
Default namespace: org.corfield.new
this doesn’t show much which is a shame, because the functions in default namespace have nice docstrings on themI'm not at a computer to test this but something like clojure -A:deps -Tnew help/doc
maybe?
@U66G3SGP5 Now I'm at a computer, I can confirm that does indeed work.
What’s the purpose of -A:deps in that command?
It adds the built-in :deps
alias which is what makes help/doc
available.
The :deps
alias is normally used with -X
for the core tooling around pom files and dependency trees etc.
Thank you
🧵 In JS when one has a symbol x defined as 5 one can use this syntax { x }
and you will be able to access the result as a map { "x" 5 }
which seems neat. So I tried to come with a macro to do something similar but I'm having some issues so am hoping that someone could help a novice macromancer (that's me and I hope it's not offensive to call myself that 😇 )
(defmacro syms->m
[syms]
`(do (into {} (map ~(fn [k v]
[(keyword k) v])
'~syms [~@syms]))))
I'm thinking it's do with the way the calls are either [x y]
or [[ x y ]]
but, assuming that's right, I'm not sure where to apply the guardrails?
I like this version
(defmacro locals [& xs]
(zipmap (map keyword xs) xs))
(let [x 1 y 2]
(locals x y))
(defn use-locals-map
[& {:keys [x y] :as opts}]
(locals x y))
(defn use-locals-list
[& xs]
(locals xs))
(let [x 1 y 2]
(use-locals-map {:x x :y y}))
=> {:x 1, :y 2}
(let [x 1 y 2]
(use-locals-list x y))
=> {:xs (1 2)}
I don't think it can work for that, call by value or call by need languages won't support it
I think you could because reader tags are run at compile time. Even though the implementations are functions, those functions are producing code, not evaluating stuff.
(defn locals-reader [v]
(zipmap (map keyword v) v))
(binding [*data-readers* {'locals #'locals-reader}]
(eval
(read-string "(let [x 1, y 2]
(println #locals[x y]))")))
;; {:x 1, :y 2}
Read/eval voodoo is only there to demonstrate in the REPL that it works. For actual usage, you add your reader function to *data-readers*
before any namespace using that reader tag is evaluated, and it should work.
Data Readers if I remember correctly are actually read time. So they run before macros.
Yes, my bad. It is why I had to use read-string
in the example, I couldn't pass the quoted form to eval
because it failed right as the form was read.
yes - if I use a function rather than a macro the reader function works from data_readers.clj
as long as it's required as you say @U06PNK4HG
I'm not sure whether
(let [x 1 y 2]
#s->m [x y])
is really any better than
(let [x 1 y 2]
(s->m [x y]))
and the latter ensures that the function / macro is requiredYeah, it's pretty minor. The main benefit from reader tags is that you lose a set of wrapping parens; unless you use the same tag really often, it's not a big deal to justify the complexity.
You don't even lose a set of wrapping parens if you go with & xs though. So ya, don't think here the reader tag is really useful. In fact, in general, this is why reader tags aren't used much. It doesn't save you a lot of typing. Also the non-namespaced ones are supposed to be reserved to Clojure (in that they could add a core one that clashes with yours otherwise). And if you add a namespace to the tag, it's even longer to type
Where reader tags are good, is for what it's called: "reading". So if you defined a new data-structure, that you want to also then serialize into EDN and back.
yeah - I've used them for crypto stuff which is complex to reconstruct so doesn't really seem worth the bother here, it was fun hour in the sandpit with you lads though
oh and for completeness complex tags need a print-method
defined - the fact that it's not needed here is another sign that it's not worth it
I like that, ya, if you don't need to extend print so i prints back as a literal tag, it's probably a bad use of reader tags.
I had a valid use for reader tags once, for a case where they had to be used a lot (think 20-30 per file) and represented a thing with a distinctive domain meaning and identity. What also helped is that they looked like "syntax" instead of regular code, and it was easier for the users (domain-aware programmers) to understand and remember that only specific things could be written inside the tagged form, not arbitrary code.
i have this macro for this https://github.com/valerauko/kitsune/blob/e88ce12da3c630f57ff18cafd04c3fee1125fa6f/api/src/kitsune/lang.clj#L3-L12
It works more like the JS literal. You can mix symbols and not-symbols, so you can write something like
(let [a 1
b 2]
(... a b :c 3))
Why does the Cognitect test runner not have a throws?
feature?
Test runner just runs tests, tests themselves are defined using clojure.test (or anything compatible) and clojure.test very much does have a thrown? thing, but it only works with the clojure.test assertion system, it isn't a standalone function/macro https://github.com/clojure/clojure/blob/4b9eadccce2aaf97e64bcc8e35c05c529df8fdd2/src/clj/clojure/test.clj#L504
Interesting, I've pasted code from doc into clj repl. I was expecting it to swallow the exception, but that is because I'm not in runner context...
user=> (require '[clojure.test :refer [deftest is testing ]] )
nil
user=> (is (thrown? ArithmeticException (/ 1 0)))
#error {
:cause "Divide by zero"
:via
[{:type java.lang.ArithmeticException
:message "Divide by zero"
:at [clojure.lang.Numbers divide "Numbers.java" 190]}]
:trace
[[clojure.lang.Numbers divide "Numbers.java" 190]
[clojure.lang.Numbers divide "Numbers.java" 3911]