LFE Style Guide

5 Naming

5.1 Symbol Guidelines

Use lower case for all symbols. Consistently using lower case makes searching for symbol names easier and is more readable. You should follow the rules for Spelling and Abbreviations You should follow punctuation conventions.

Note that, unlike Common Lisp, LFE is not case-converting, and that the symbol-name of your symbols will be lowercase. As such, FUNC and func would represent two different functions. Regarldess, we encourage all LFEers to use the Common Lisp standards and not mix case: keep it simple.

Place hyphens between all the words in a symbol. If you can't easily say an identifier out loud, it is probably badly named.

You must not use "/" or "." instead of "-" unless you have a well-documented overarching reason to, and permission from other hackers who review your proposal.

See the section on Spelling and Abbreviations for guidelines on using abbreviations.

;; Bad
(defun default-username () '"Ann")
(defun max-widget-cnt () 200)
;; Better
(defun default-user-name () '"Ann")
(defun maximum-widget-count () 200)

There are conventions in Common Lisp for the use of punctuation in symbols. You should not use punctuation in symbols outside these conventions.

Unless the scope of a variable is very small, do not use overly short names like i and zq.

5.2 Denote Intent, Not Content

You should name a variable according to the high-level concept that it represents, not according to the low-level implementation details of how the concept is represented.

Thus, you should avoid embedding data structure or aggregate type names, such as list, tuple, or atom inside variable names, unless you're writing a generic algorithm that applies to arbitrary lists, tuples, atoms, etc. In that case it's perfectly OK to name a variable list or tuple.

Be consistent. If a variable is named row in one function, and its value is being passed to a second function, then call it row rather than, say, value.

5.3 Global Variables and Constants

Global variables should be avoided whenever possible. In Common Lisp, the following convention is followed:

  • Global constants start and end with plus characters +.
  • Global variable names start and end with asterisks * (also known in this context as "earmuffs").

Examples:

(defun +hash-results+ () #xbd49d10d10cbee50)
(defun *maximum-search-depth* () 100)

In LFE, while we won't say this is a bad practice, we'd suggest you do things a little differently. (You may find that some LFE projects will reject a pull request with global constants or variables, or ones named in the Common Lisp manner.)

The prefered method is to define a constants module for your project, such as my-proj-const.lfe. Then, you can refer to that project's constants with calls like (my-proj-const:max-widgets). The use of a constants module like this provides the same context as +name+ or *name* without the need for such things as "earmuffs".

Keep in mind that, unlike Common Lisp, LFE doesn't have (defvar ...) or (defconstant ...) forms. Instead, functions are used (functions which take no arguments).

In some projects, parameters that are not meant to be usually modified or bound under normal circumstances (but may be during experimentation or exceptional situations) should start (but do not end) with a dollar sign. If such a convention exists within your project, you should follow it consistently. Otherwise, you should avoid naming variables like this.

5.4 Predicate Names

Due to the influence of Clojure, LFE supports two conventions for naming predicates:

  • A trailing p or -p, or
  • A trailing ?.

You should name boolean-valued functions and variables with a trailing "?", "P", or "-P", to indicate they are predicates. When choosing the Common Lisp convention, you should use "P" when the rest of the function name is one word and "-P" when it is more than one word.

A rationale for this convention is given in the CLtL2 chapter on predicates.

When you develop such a package and decide upon a convention for your predicates, you should be consistent with the rest of the package. When you start a new package, you should not use an alternative rule without a very good documented reason.

5.5 Modules

Erlang doesn't have packages, and LFE inherits this approach to module management. Filenames and module names need to match, and they need to be unique across all installed libraries and services. As such, LFE gets namespaces in the form of module names, and conventions such as prefixing modules with unique atoms (such as the project name) make this approach usable.

Only functions which have been explicitly exported (or all functions, in the case of an (export all)) are accessible outside the module.

You may find that some internal symbols represent concepts you usually want to abstract away and hide under the hood, yet at times are necessary to expose for various extensions. For the former reason, you do not want to export them, yet for the latter reason, you have to export them. The solution is to have two different modules, one for your normal users to use, and another for the implementation and its extenders to use.

Your module cannot shadow core LFE forms (and thus can't effectively redefine) symbols that are part of the LFE language. For forms that are shadowable, we strongly discourage this practice. There are certain exceptions, but they should be very well-justified and extremely rare:

  • If you are explicitly replacing an Erlang or LFE symbol with a safer or more featureful version. (If this is the case, you should also submit a patch upstream so that others may benefit from this improvement.)
  • If you are defining a module not meant to be "used", and have a good reason to export a symbol that clashes with LFE.