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.:requirewith:asgives an alias (str/join);:referimports specific names unqualified (use it sparingly).:importbrings 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).