Would love to hear folks experiences with and thoughts about namespace-qualified keywords -- I was thinking about this particularly in the context of the current podcast series.
I love the idea of passing maps around and being able to sneak any potentially useful context around in those maps and using namespace-qualified keywords as your map keys avoids potential name collisions and documents who is responsible for that data (and serves to group related keys together -- though same could be done by putting multiple things together in a sub-map).
That being said, I often use keywords as functions and use key-based destructuring, and both of these are less convenient with namespace-qualified keywords than with "bare" keywords. Further, when there's a mix of :some.namespace/foo , ::foo, and ::somealias/foo all referring to the same keyword, it's more difficult to track down all the references to a given keyword.
Am I doing it wrong? Do I just need to embrace namespace-qualified keywords everywhere and get used to it (until it doesn't feel inconvenient anymore)?
Or maybe it's just better to avoid the ::kw and ::somealias/kw syntax and stick to :some.namespace/foo everywhere?
::kw causes tons of problems, and I generally avoid it unless it's more or less a private member.
::alias/kw works with tooling just fine
at least it does with intellij. I would assume kondo, cider, and Calva all have proper support as well
that said, for all the reasons you listed, I tend to type out a short namespace anyways
:aws.s3/key or :user/name
you only need a long namespace when you're writing a library
when you use a short keyword namespace, there's also no need to make it align with a particular code namespace
I also tend to avoid ::kw. And I tend to go with namespaced keywords that are not aligned with actual namespaces. I call it “synthetic” namespaces. Calva (by proxy of clojure-lsp/clj-kondo) loves all kinds of namespaced keywords.
I was asked recently on a podcast if I would change anything about Clojure. I couldn't think of anything, but I wish I had said that I would probably like to remove features instead of adding them. E.g. *print-namespace-maps* , but mostly because I feel the pain when writing tooling for those features 😅
I also dislike that feature and how difficult it is to disable it.
But ‘tis a mere nuisance
Yeah, not a big deal
I also use {:foo/keys [bin baz]} often, but if I just have one thing, I'll use the full key name eg. {the-thing :the/thing}
Here's an example from actual code:
{:cache/keys [url-settings settings]
:device/keys [registered? started?]
:websocket/keys [connected?]} dataI have state information that looks like:
(defn initial-data
[]
{:device/connections {}
:device/duplicate? false
:device/id nil
:device/name nil
:device/registered? false
:device/started? false
:device/type nil
:org/id nil
:websocket/connected? false})The :entity/name thing bothers me a lot, I hate shadowing core fns. I often end up making more verbose attributes like :device/device-name :book/book-id so that code using {:book/keys [book-id]} (vs, just id ) is more readable. Some people I've worked with definitely disagree though. I suppose its about optimizing for different things: reading code vs writing code perhaps
I’ve wasted more time than i want to admit from shadowing fns (not just core). I just don’t do it. Going longer is one option, but going shorter is as well.
Agreed!! I think clj-kondo has a linter to catch shadowing, you just have to set up a list of cars you want to avoid shadowing.
I never actually considered going smaller, opened my eyes today
I like to use the names Clojure.core uses: k, v, m, nm, ...
(for binding and parameter names; I think nm is awkward in an API)
I use that all the time!
I try to avoid overshadowing Clojure core names. So even if a keyword like :user/name makes sense, destructuring it like [{:user/keys [name]}] can cause troubles. Especially together with tools like Snitch. So it will be :user/user-name .
I don’t, but it’s mostly a preference thing. I’ve been bitten by shadowing a ton so I shorten all names to abbreviations by default to avoid it.
{n :user/name}
Eg
It’s wonderful, I think:
(defn foo [{:foo/keys [...]
:bar/keys [...]}]
...)
Agreed about shadowing -- I use nm, k, v, ks, vs, m etc; shadowing map has bitten me too many times
most people recoil when they see the abbreviations I use, but everyone who’s worked with me ends up liking it.
the abbreviations are always consistent, which helps.
Also sometimes [{:keys [foo/this bar/that]}]
I use the abbreviations already used in core whenever I can
x ❤️
Yeah I basically do that all over the place. organization -> org, last-modified-date -> lmd, username -> un, etc
used consistently, it becomes an easy shorthand. people would even say them out loud
I tend to use longer names. And short ones for functions sent to higher order functions in core and libs.
acc for the reduce accumulator. I know some people hate it, but to me it just says exactly what I want it to say. It is the accumulator. 😃