This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-04-18
Channels
- # ai (2)
- # announcements (11)
- # beginners (34)
- # biff (14)
- # clerk (14)
- # clj-kondo (25)
- # clojure (27)
- # clojure-austin (1)
- # clojure-conj (6)
- # clojure-denmark (1)
- # clojure-europe (20)
- # clojure-hamburg (1)
- # clojure-nl (1)
- # clojure-norway (28)
- # clojure-uk (2)
- # clojuredesign-podcast (6)
- # clojurescript (43)
- # cursive (4)
- # data-science (2)
- # emacs (9)
- # hyperfiddle (9)
- # introduce-yourself (2)
- # jobs (3)
- # lsp (32)
- # missionary (31)
- # nbb (8)
- # off-topic (23)
- # rdf (23)
- # re-frame (10)
- # reitit (11)
- # releases (3)
- # rewrite-clj (4)
- # shadow-cljs (7)
- # specter (6)
- # sql (7)
- # xtdb (7)
Hey everyone, is it possible to define a keyword inside a protocol?
(defprotocol IProt
(:example [p]))
what do you want to achieve by that?
keyword doesn't have behaviour. it is simple function that can be translated to (get m :keyword)
to override how keyword works if applied to an object you have to ensure that this object implements (overriding original implementation) this interface https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ILookup.java#L15
so it is possible but please don't do that 🙂 that would be very hard to maintain
While I agree that you don’t generally want to do this unless you really know what you’re doing, you prompted me to go diffing in the clojure source code. Lessons:
1. When you run (:example thing)
, it runs clojure.lang.Keyword.invoke
, which runs thing.valAt(:example)
(https://github.com/clojure/clojure/blob/4090f405466ea90bbaf3addbe41f0a6acb164dbb/src/jvm/clojure/lang/Keyword.java#L146-L150)
2. valAt is part of the https://github.com/clojure/clojure/blob/4090f405466ea90bbaf3addbe41f0a6acb164dbb/src/jvm/clojure/lang/ILookup.java#L15
In other words, you can change the behavior of (:example thing)
by implementing the ILookup
interface on the type of thing.
That’s not exactly what you asked for (defining a keyword inside a protocol), but it will allow you to change what happens when someone uses keywords to access properties from your object!
(sorry for the long digression, feel free to ignore this comment if you want to get on with your day 🙂)
If I have a bunch of bindings from a let, e.g. (let [x “1” y “2" z “3”] is there a fast way to turn those in to a map? like {:x “1" :y “2” :z “3"} ..sort of like select-keys but they aren’t in a map yet, just to avoid repeating stuff like {:x x :y y :z z}
you can use macro for that:
(defmacro bindings->map [& bindings]
(let [keys (into [] (map keyword) bindings)]
`(let [vals# [~@bindings]]
(zipmap ~keys vals#))))
(let [x 1 y 2]
(bindings->map x y))
;; => {:x 1 :y 2}
What are the advantages of using a macro for this? Instead of a normal function.
awesome, I have feared macros to this point, but this looks like a good My First Macro (other than the ones I use all time without thinking about it … let.. fn… lol
Yeah, this kind of simple macro is a good exercise. Feel free to ping me if you need me to explain some bits and peaces
made a little update, now supports namespaced keywords
(defmacro bindings->map [& bindings]
(let [keys (into [] (map #(keyword (namespace %) (name %))) bindings)
syms (into [] (map (comp symbol name)) bindings)]
`(let [vals# [~@syms]]
(zipmap ~keys vals#))))
(let [x 1 y 2]
(bindings->map x/x y/y))
;; => {:x/x 1, :y/y 2}
gotta caution using something like this though, it's not a idiom in clojure. most text editors have tools that make writing out the key/vals for objects automatic. and it's pretty common to use key names that are different from the assigned symbols.
i've recently run into a weird situation where starting a REPL hangs indefinitely when trying to download Clojure. it seems to be downloading from an additional :mvn/repos
key that i have configured in my project's deps.edn, which is a private maven repo. the few dependencies before it (omitted) download without an issue. any ideas? :thinking_face:
$ clj -Mdev
...
...
Downloading: org/clojure/clojure/maven-metadata.xml from release
Maven will (potentially) try to download from any of the repos you have listed
the maven metadata is particularly downloaded when checking for the latest version of something, any chance you're doing that somehow (using RELEASE as a version, etc)
hi Alex! nope, i’m not using release as a version. deps.edn
looks like so:
{:mvn/repos {"datomic-cloud" {:url "s3://<redacted>/maven/releases"}
"release" {:url "s3://<redacted>>"}
"snapshot" {:url "s3://<redacted>"}
"mulesoft" {:url ""}
"cognitect-dev-tools" {:url " "}}
:aliases {:dev {:jvm-opts ["<redacted>"]
;; Alphabetically sorted
:extra-paths ["<redacted>"]
:extra-deps {org.clojure/clojure {:mvn/version "1.11.1"}
"<redacted...>"}}
:test {;; Alphabetically sorted
:extra-paths ["<redacted...>"]
:extra-deps {"<redacted but no extra deps for Clojure"}}}}
when it hangs like that, can you get a stack trace? you can see the Java processes running with jps -mV | grep tools
to get the pid, then jstack <the-pid>
alternately, you could try debugging directly by using tools.deps in a repl. kind of hard for me to debug without all the stuff
yup, will do. fortunately that haunted machine is in the office and i’m home with my working one, which is on the same code base and works just fine. weird, right? i’ll post a stack trace tomorrow and if you happen to see it then great, but don’t sweat it 🙂
also, please make sure you're on the latest clj of course
hi @U064X3EF3 upgrading the clj cli fixed my issue. many thanks for your help.
==> Upgrading clojure/tools/clojure
1.10.3.986 -> 1.11.1.1273
Does anyone have an article/resource to read on the rationale between using truey/falsey returns (the value/nil), vs returning true/false? Been doing a bit of both, trying to figure out which practice to adopt and why.
Due to the pervasive use of logical truth values, it rarely matters
I see. Will settle on truey/falsey for now, but any related reading is appreciated! Thanks
About the only "convention" that folks seem to hold to is that if a function name ends in ?
there's an expectation that it specifically returns true
or false
-- but otherwise lots of functions can return nil
or some value and therefore can end up being used as predicates (returning truthy -- "some value" -- or falsey -- nil
).
Yeah, I wasn’t even aware that was an expectation, but now I know 😄 Thanks for the input!
an advantage of returning real values or nil is that you can use or
to provide a list of options with fallbacks. Here’s an example from Neil’s source:
(or
(when-let [v (:version opts)]
[v :mvn])
(when-let [v (latest-stable-clojars-version lib)]
[v :mvn])
(when-let [v (latest-stable-mvn-version lib)]
[v :mvn])
(when-let [v (git/latest-github-sha lib)]
[v :git/sha])
(when-let [v (latest-clojars-version lib)]
[v :mvn])
(when-let [v (latest-mvn-version lib)]
[v :mvn]))
The first matching “or branch” hits. So we try a user-selected version first. Then we try a stable version from clojars. Then we try a stable version from maven. You get the gist 🙂
https://github.com/babashka/neil/blob/19bc12d1c868eb5c1f200963c240a2a107982556/src/babashka/neil.clj#L365-L377