Skip to content
AgileLogics
6 min read

Namespaces

Prerequisites: Functions

A namespace groups related definitions and is Clojure's unit of code organization — one namespace per file.

Declaring a namespace

;; illustrative — src/shop/pricing.clj
(ns shop.pricing
  "Prices, discounts, and tax."
  (:require [clojure.string :as str]
            [clojure.set :refer [union]]
            [shop.catalog :as catalog])
  (:import (java.time LocalDate)
           (java.util UUID)))

(def tax-rate 0.2)

(defn- round2 [x]                   ; defn- = private
  (/ (Math/round (* x 100.0)) 100.0))

(defn price-with-tax [sku]
  (round2 (* (catalog/price sku) (+ 1 tax-rate))))
  • (ns name ...) names the namespace and declares dependencies.
  • :require with :as gives an alias (str/join); :refer imports specific names unqualified (use it sparingly).
  • :import brings in Java classes by short name.
  • defn- makes a function private to the namespace.

Files and names

The namespace shop.pricing lives in src/shop/pricing.clj. Dots become folders, and dashes become underscores in file names: my-app.order-service is src/my_app/order_service.clj. Getting this wrong is the most common "Could not locate ... on classpath" error.

Namespaces in one file

(ns shop.catalog)

(def ^:private prices {"pen" 1.5 "book" 12.0})
(defn price [sku] (get prices sku 0))

(ns shop.core
  (:require [shop.catalog :as catalog]))

(println (catalog/price "book"))
(println (shop.catalog/price "pen"))
(println (ns-name *ns*))
(println (sort (keys (ns-publics 'shop.catalog))))
12.0
1.5
shop.core
(price)

Normally each namespace is its own file; this demo defines two in one script to show how they relate. Every var has a fully qualified name (shop.catalog/price); aliases are just shortcuts. ^:private marks a def private.

Namespaces at the REPL

user=> (require '[shop.pricing :as p] :reload)   ; load or reload a file
user=> (in-ns 'shop.pricing)                      ; switch namespace
shop.pricing=> (price-with-tax "book")
14.4
shop.pricing=> (dir clojure.string)               ; list a namespace's functions

Editors do this for you — "load file" sends the whole namespace to the REPL, and evaluation happens in the file's namespace.

Main entry points

;; illustrative — src/shop/main.clj, run with: clj -M -m shop.main 3
(ns shop.main
  (:gen-class))

(defn -main [& args]
  (println "Starting with" (count args) "argument(s):" args))

clj -M -m shop.main loads the namespace and calls its -main function with the command-line arguments. (:gen-class) is needed when you build an executable jar (Level 3).