44

What are the best practices for defining constants in Clojure in terms of style, conventions, efficiency, etc.

For example, is this right?

(def *PI* 3.14)

Questions:

Should constants be capitalized in Clojure?

Stylistically, should they have the asterisk (*) character on one or both sides?

Any computational efficiency considerations I should be aware of?

Julien Chastang
  • 17,592
  • 12
  • 63
  • 89
  • 4
    Also remember that, whatever you end up naming it, your might want to give it const metadata: `(def ^:const pi 3.14)` – jemmons Feb 28 '13 at 03:19
  • 1
    I prefer to just assume everything is a constant unless otherwise specified, as https://github.com/bbatsov/clojure-style-guide advises. – mk12 May 04 '14 at 14:31
  • seems like it would be useful to have a way to make something constant for uses in things like case statements no? – leeor Aug 30 '15 at 19:08

7 Answers7

24

I don't think there is any hard and fast rules. I usually don't give them any special treatment at all. In a functional language, there is less of a distinction between a constant and any other value, because things are more often pure.

The asterisks on both sides are called "ear muffs" in Clojure. They are usually used to indicate a "special" var, or a var that will be dynamically rebound using binding later. Stuff like out and in which are occasionally rebound to different streams by users and such are examples.

Personally, I would just name it pi. I don't think I've ever seen people give constants special names in Clojure.

EDIT: Mister Carper just pointed out that he himself capitalizes constants in his code because it's a convention in other languages. I guess this goes to show that there are at least some people who do that.

I did a quick glance through the coding standards but didn't find anything about it. This leads me to conclude that it's really up to you whether or not you capitalize them. I don't think anyone will slap you for it in the long run.

Community
  • 1
  • 1
Rayne
  • 31,473
  • 17
  • 86
  • 101
  • 1
    I capitalize my constants, because it's a common convention in other languages. See also `Math/PI` in Java. – Brian Carper Aug 26 '10 at 20:21
  • 1
    I'm sure a few people do, at the very least, but I haven't seen it in any code I've looked at insofar. I don't think there is any of that in core either. It doesn't appear to be a part of the http://www.assembla.com/wiki/show/clojure/Clojure_Library_Coding_Standards coding standards, so I suppose it's up to the individual. – Rayne Aug 26 '10 at 20:25
  • however i use capitalization for "type" definitions (including structs) to create a conventional, separate name space for them (defstruct Foo :key1) – jneira Aug 27 '10 at 06:10
  • I don't think this argument holds, because regardless of the fact that you're not going to mutate a binding, the benefit of having a convention for constants lies in the implication to the reader that they will be able to find the definition at the top of this or another compilation unit's source file, and this value will be statically determinable before the program runs. – amoe Feb 23 '16 at 13:13
13

On the computational efficiency front you should know there is no such thing as a global constant in Clojure. What you have above is a var, and every time you reference it, it does a lookup. Even if you don't put earmuffs on it, vars can always be rebound, so the value could always change, so they are always looked up in a table. For performance critical loops this is most decidedly non-optimal.

There are some options like putting a let block around your critical loops and let the value of any "constant" vars so that they are not looked up. Or creating a no-arg macro so that the constant value is compiled into the code. Or you could create a Java class with a static member.

See this post, and the following discussion about constants for more info:

http://groups.google.com/group/clojure/msg/78abddaee41c1227

pjstadig
  • 266
  • 1
  • 4
  • I think "there is no such thing as a global constant in Clojure" is as important philosophically as it is from an efficiency view-point. That said the linked discussion is very helpful in giving a practical example of what is going on with vars. – Alex Stoddard Aug 30 '10 at 21:34
  • 2
    There is, if you add ^:const to a Var it will in-line the Var, that is, it'll look up the value once when the namespace is loaded, and it'll replace everything using the Var with the value itself. – Didier A. Oct 18 '15 at 23:40
8

The earmuffs are a way of denoting that a given symbol will have its own thread-local binding at some point. As such, it does not make sense to apply the earmuffs to your Pi constant.

*clojure-version* is an example of a constant in Clojure, and it's entirely in lower-case.

Anders
  • 856
  • 1
  • 7
  • 14
  • Yet it makes no sense to consider `*clojure-version*` thread local. It seems the ear-muffs convention is not as specific as your answer implies. – Alex Stoddard Aug 30 '10 at 21:40
  • Although I have just discovered the clojure coding conventions http://www.assembla.com/wiki/show/clojure/Clojure_Library_Coding_Standards . There the earmuffs style is specified only for things that should be rebound. – Alex Stoddard Sep 02 '10 at 14:42
  • 4
    Yes, rebound/thread local binding. But why *clojure-version* is supposed to be rebound is beyond me. – Anders Sep 03 '10 at 07:53
  • Document for Coding Standards has moved to here http://dev.clojure.org/display/community/Library+Coding+Standards – Reb.Cabin Apr 05 '17 at 12:45
6

Don't use a special notation for constants; everything is assumed a constant unless specified otherwise.

See http://dev.clojure.org/display/community/Library+Coding+Standards

dkinzer
  • 32,179
  • 12
  • 66
  • 85
espeed
  • 4,754
  • 2
  • 39
  • 51
1

In Common Lisp, there's a convention of naming constants with plus signs (+my-constant+), and in Scheme, by prefixing with a dollar sign ($my-constant); see this page. Any such convention conflicts with the official Clojure coding standards, linked in other answers, but maybe it would be reasonable to want to distinguish regular vars from those defined with the :const attribute.

I think there's an advantage to giving non-function variables of any kind some sort of distinguishing feature. Suppose that aside from variables defined to hold functions, you typically only use local names defined by function parameters, let, etc. If you nevertheless occasionally define a non-function variable using def, then when its name appears in a function definition in the same file, it looks to the eye like a local variable. If the function is complex, you may spend several seconds looking for the name definition within the function. Adding a distinguishing feature like earmuffs or plus signs or all uppercase, as appropriate to the variable's use, makes it obvious that the variable's definition is somewhere else.

In addition, there are good reasons to give special constants like pi a special name, so no one has to wonder whether pi means, say, "print-index", or the i-th pizza, or "preserved interface". Of course I think those variables should have more informative names, but lots of people use cryptic, short variable names, and I end up reading their code. I shouldn't have to wonder whether pi means pi, so something like PI might make sense. None would think that's a run of the mill variable in Clojure.

Mars
  • 8,689
  • 2
  • 42
  • 70
1

Clojure has a variety of literals such as:

3.14159
:point
{:x 0 
 :y 1}
[1 2 3 4]
#{:a :b :c}

The literals are constant. As far as I know, there is no way to define new literals. If you want to use a new constant, you can effectively generate a literal in the code at compile-time:

(defmacro *PI* [] 3.14159265358979323)
(prn (*PI*))
jhuni
  • 425
  • 3
  • 4
0

According to the "Practical Clojure" book, it should be named *pi*

Aymen
  • 558
  • 6
  • 13