1

I am having lots of "fun" trying to understand why the below won't work. After starting an nREPL session in the src directory of my lein project, I did the following:

user> (require 'animals.core)
nil
user> (animals.core/-main)
"Welcome to Animals!"
nil
user> (require 'animals.animal)
nil
user> (extends? animals.animal/Animal animals.animal/Dog)
CompilerException java.lang.RuntimeException: No such var: animals.animal/Dog, compiling:(NO_SOURCE_PATH:1:1)

Reading the Lein tutorial, my basic understanding is that I should place my source like so:

- src/
|____ animals/
      |_______ core.clj
      |_______ animal.clj

Where the contents of animal below look like this:

(ns animals.animal)

(defprotocol Animal
  "A protocol for animal move behavior."
  (move [this] "Method to move."))

(defrecord Dog [name species]
  Animal
  (move [this] (str "The " (:name this) " walks on all fours.")))

(defrecord Human [name species]
  Animal
  (move [this] (str "The " (:name this) " walks on two legs.")))

(defrecord Arthropod [name species]
  Animal
  (move [this] (str "The " (:name this) " walks on eight legs.")))

(defrecord Insect [name species]
  Animal
  (move [this] (str "The " (:name this) " walks on six legs.")))

Why would a runtime exception result from attempting to evaluate Dog when evaluating Animal resulted in no error? How does one go about doing this correctly?

dtg
  • 1,803
  • 4
  • 30
  • 44

1 Answers1

3

Animal is a protocol. A protocol has an associated Var in the namespace in which it is defined. It is through this Var that one refers to a protocol.

In contrast, Dog is a record. Records are just classes and have no Vars corresponding to them. (Well, there are factory functions stored in Vars, but you cannot refer to the record itself through those factory functions.) Thus, to refer to a record, you need to use different syntax: animals.animal.Dog.

Michał Marczyk
  • 83,634
  • 13
  • 201
  • 212
  • Thank you. Also, is there a way to invoke these items without specifying the whole namespace? For example, executing `(use 'animals.animal)` and then executing `(extends? Animal Dog)` doesn't appear to work. – dtg Jun 15 '13 at 22:59
  • Apparently `(import [animals.animal Dog])` did the trick. The duality of syntax seems to be result of `defrecord` compiling to a Java class... – dtg Jun 15 '13 at 23:16
  • Yes. That's what I meant to say in the second paragraph of the answer. – Michał Marczyk Jun 15 '13 at 23:44