Clojure is not an object-oriented language like Java or Python. When someone mentions “objects” in Clojure, they’re usually using that term in the generic sense (as in, “objects such as numbers, strings, functions, data structures, Atoms, Agents, etc.”) — not in the sense of OO-style objects.
Clojure is a functional language. You spend much of your time using and writing functions. And note that functions may take other functions as arguments (and may also return functions).
Clojure is a Lisp-dialect, and is also similar to other high-level scripting languages you may have used. It has built-in data structures and a variety of handy functions for operating on them. But there’s one big difference: all Clojure values (numbers, strings, data structures, etc.) are immutable. If you want one of them changed, you instead make a “whole new” data structure that is just like the original but with the one small change you wanted. This isn’t as crazy as it sounds though, because — since they’re immutable — Clojure can (and does) share data between different data structures behind the scenes.
Don’t worry if this sounds odd. Once you start going through tutorials and trying things out it begins to make sense how it works in practice.
Note: you can, of course, use Java OO-style objects in Clojure, which are usually mutable. But the core built-in bread-and-butter Clojure data structures are all immutable.
Since Clojure values aren’t mutable, it doesn’t really make sense to call them “variables” (they don’t vary). Clojure does, though, have “reference types” which act like variables. Reference types are mutable; you can change to which immutable value they refer.
A couple of notes about reference types:
- they come in 4 different flavors (Vars, Refs, Agents, & Atoms)
- the Clojure runtime helps you change to which immutable value they refer, in a managed way that ensures concurrency works reliably.
Tutorials usually discuss these reference types in later sections, after you’ve gotten the hang of basic idiomatic Clojure. Reference types are supposed to represent an “identity” — an entity that may take on different (immutable) values over time. But regardless of which value an identity currently happens to refer to, it’s still the same entity.
1 A Note on Namespaces
Every function has a fully-qualified name. For example, a function named “my-func” defined in your project’s my-proj/src/my_proj/core.clj file would have a fully-qualified name of “my-proj.core/my-func”. The part before the slash (“my-proj.core”) is the namespace of the function.
If you call my-func from somewhere within that core.clj file, you can just call it by its simple unqualified name (“my-func”); you don’t have to fully-qualify it. But if you want to call my-func from code in some other file, you have to somehow tell Clojure that you’re talking about the my-proj.core/my-func function. (We’ll get to details on how to do that later, in the chapter on managing and using libraries.)
The only exception to that rule is: you don’t need to fully-qualify Clojure’s built-in function names in order to call them. Although their namespace is clojure.core, they’re always available by their short names. For example, you can always call
(println "hi") instead of
2 Misc Java Notes
A particular strength of Clojure is how easily it allows you to use Java. Although you don’t need to know Java to use Clojure, it helps, because whenever you need a library which Clojure doesn’t have, you can easily enough use the Java solution right from your Clojure code.
A terminology note: Java has “arrays” (a fixed-size, sequential, indexable, mutable data structure). When you hear “array”, that means the Java kind. The Clojure indexable data structure is called “vector”.