Is there a canonical way to name variables that would otherwise cause name collisions?

Viewed 118

Say I'd like to name a variable seq, referring to some kind of sequence.

But seq is already a function in clojure.core, so if I try to name my variable seq, the existing meaning of seq will be overwritten.

Is there a canonical way in Clojure to name a variable that would otherwise have a name collision with a default variable?

(e.g., in this case, my-seq could be used, but I don't know whether that would be standard as far as style goes)

2 Answers

There is no "standard" way of naming things (see the quote and the related joke).

If it is a function of only one thing, I often just name it arg. Sometimes, people use abbreviations like x for a single thing and xs for a sequence, list, or vector of things.

For small code fragments, abbreviating to the first letter of the "long" name is often sufficient. For example, when looping over a map, each MapEntry is often accessed as:

(for [[k v] some-map]  ; destructure key/val into k & v
  ...)

Other times, you may prefix it with a letter like aseq or the-seq.

Another trick I often use is to add a descriptive suffix like

name-in
name-full
name-first

(yes, there is a Clojure function name).

Note that if you did name it seq, you would create a local variable that shadowed the clojure.core/seq function (it would not be "overwritten"). I often just "let it slide" if the scope of the shadowing is limited and the name in question is clear & appropriate (key and val are often victims of this practice). For name, I would also probably just ignore the shadowing of clojure.core/name, since I rarely use that function.

Note that you can shadow your own local variables. This is often handy to coerce data in to a specific format:

(defn foo
  [items]
  ; assume we need a sorted vector with no duplicates
  (let [items (vec (sort (set (items))))]
    ...))

By shadowing the original items argument, we ensure the data is in the desired form without needing to come up with two good, descriptive names. When this technique doesn't quite fit, I often fall back to the suffix trick and just name them items-in and items or similar.

Sometimes a suffix indicating type is valuable, when multiple representations are required. For example:

items
items-set
items-vec

type-str
type-kw
type-sym

There are many other possibilities. The main point is to make it clear to the reader what is happening, and to avoid creating booby traps for the unaware.

When in doubt, add a few more letters so it is obvious to a new reader what is happening.

You won't override clojure.core/seq. You will be simply shadowing the var seq with your local bindings or vars. One can always use fully qualified name to use core seq.

Example:


;; shadow core seq
(def seq [1 2 3])
WARNING: seq already refers to: #'clojure.core/seq in namespace: user, being replaced by: #'user/seq
=> #'user/seq


;; local binding 
(defn print-something [seq]
  (prn seq)
  (prn (var seq)))
=> #'user/print-something


;; use fully qualified name
(clojure.core/seq "abc")
=> (\a \b \c)


(print-something "a")
"a"
#'user/seq
=> nil


(prn seq)
[1 2 3]
=> nil


(var seq)
=> #'user/seq

But, its not a clean practice to shadow clojure.core vars as it might lead to buggy code. It does more harm than good if any. I usually name vars based on code context, like employee-id-seq, url-seq etc. Sometimes, it okay to use short names like x or s if usage scope is limited. You can also see clojure.core implementation to find more examples.

A good guide: https://github.com/bbatsov/clojure-style-guide#idiomatic-names

I also recommend clj-kondo plugin

Related