Dynamic typing is cool, but sometimes you just want to know the type of something.
I’ve seen people write this:
(isa? (type x) SomeJavaClass)
As its docstring describes,
isa? checks inheritance relationships, which may come from either Java class inheritance or Clojure hierarchies.
isa? manually walks the class inheritance tree, and has special cases for vectors of types to support multiple-argument dispatch in multimethods.
;; isa? with a vector of types. ;; Both sequences and vectors are java.util.List. (isa? [(type (range)) (type [1 2 3])] [java.util.List java.util.List]) ;;=> true
Hierarchies are an interesting but rarely-used feature of Clojure.
(derive java.lang.String ::immutable) (isa? (type "Hello") ::immutable) ;;=> true
If all you want to know is “Is x a Foo?” where Foo is a Java type, then
(instance? Foo x) is simpler and faster than
(instance? String "hello") ;;=> true (instance? Double 3.14) ;;=> true (instance? Number 3.14) ;;=> true (instance? java.util.Date #inst "2015-01-01") ;;=> true
instance? takes the type first, opposite to the argument order of
isa?. This works nicely with
(defn make-bigger [x] (condp instance? x String (clojure.string/upper-case x) Number (* x 1000))) (make-bigger 42) ;;=> 42000 (make-bigger "Hi there") ;;=> "HI THERE"
instance? maps directly to Java’s Class.isInstance(Object). It works for both classes and interfaces, but does not accept
nil as a type.
(isa? String nil) ;;=> false (instance? String nil) ;;=> false (isa? nil nil) ;;=> true (instance? nil nil) ;; NullPointerException
deftype produce Java classes as well:
(defrecord FooBar [a]) (instance? FooBar (->FooBar 42)) ;;=> true
Remember also that records and types are classes, not Vars, so to reference them from another namespace you must
:import instead of
instance? won’t work correctly with Clojure protocols. To check if something supports a protocol, use