Clojure

Using Libs

Clojure provides for code loading and dependency tracking via its "lib" facility. A lib is a named unit of Clojure source code contained in a Java resource within classpath. A lib will typically provide the complete set of definitions that make up one Clojure namespace.

Lib Conventions

Clojure defines conventions for naming and structuring libs:

  • A lib name is a symbol that will typically contain two or more parts separated by periods.

  • A lib’s container is a Java resource whose classpath-relative path is derived from the lib name:

    • The path is a string

    • Periods in the lib name are replaced by slashes in the path

    • Hyphens in the lib name are replaced by underscores in the path

    • The path may end with ".class", ".clj", or ".cljc" (see Lib load order below)

  • A lib begins with an "ns" form that

    • creates the Clojure namespace that shares its name, and

    • declares its dependencies on Java classes, Clojure’s core facilities, and/or other libs,

Clojure ensures that if the call to "ns" completes without throwing an exception, the declared dependencies have been satisfied and the capabilities they provide are available.

Example Lib

A simple lib:

(ns com.my-company.clojure.examples.my-utils
  (:import java.util.Date)
  (:use [clojure.string :only (join)])
  (:require [clojure.java.io :as jio]))
  • The ns form names the lib’s namespace and declares its dependencies. Based on its name, this lib is typically defined in a source file at the classpath-relative path: com/my_company/clojure/examples/my_utils.clj (note the translations from period to slash and hyphen to underscore).

  • The :import clause declares this lib’s use of java.util.Date and makes it available to code in this lib using its unqualified name.

  • The :use clause declares a dependency on the clojure.string lib for its join function only. join may be used in this lib’s code using its unqualified name.

  • The :require clause declares a dependency on the clojure.java.io lib and enables using its members using the shorter namespace alias jio.

Prefix Lists

It’s common for a lib to depend on several other libs whose full names share a common prefix. In calls to require and use (and in :require and :use clauses within an ns form), the common prefix can be extracted and provided once using a prefix list. For example, these two forms are equivalent:

(require 'clojure.contrib.def 'clojure.contrib.except 'clojure.contrib.sql)
(require '(clojure.contrib def except sql))

Creating a namespace: ns

Ensuring a lib is loaded: require use

Listing loaded libs: loaded-libs

Lib load order

Libs may exist in either compiled (.class) or source (.clj or .cljc) form. In some cases, one or even all of these might exist on the classpath. The lib is loaded from one of them based on the following rules:

  • A .class file is always preferred over a source file, unless the source file’s timestamp is newer than the .class file, in which case the source file is preferred.

  • A .clj (platform-specific file) is always preferred over a .cljc (common across platforms).

The second rule allows a library author to ship both a portable common definition of a lib while also shipping platform-specific libs that override the portable version to do something that leverages the host platform.