There are two ways to implement a protocol for any given type:
Provide implementations for protocol methods when a type is
initially defined via
defrecord; this is called
extend* functions to
register implementations for a type with the protocol.
Example 6-3. Implementing a protocol inline
(defrecord Point [x y] Matrix (lookup [pt i j] (when (zero? j) (case i 0 x 1 y))) (update [pt i j value] (if (zero? j) (condp = i 0 (Point. value y) 1 (Point. x value)) pt)) (rows [pt] [[x] [y]]) (cols [pt] [[x y]]) (dims [pt] [2 1]))
Example 6-4. Extending a protocol to an already-defined type
(defrecord Point [x y]) (extend-protocol Matrix Point (lookup [pt i j] (when (zero? j) (case i 0 (:x pt) 1 (:y pt)))) (update [pt i j value] (if (zero? j) (condp = i 0 (Point. value (:y pt)) 1 (Point. (:x pt) value)) pt)) (rows [pt] [[(:x pt)] [(:y pt)]]) (cols [pt] [[(:x pt) (:y pt)]]) (dims [pt] [2 1]))
A minor difference between the two approaches is how you access
field values: when you extend a type externally you have to access the
types’ fields using keywords (or interop forms like
(.x pt)), while when you provide inline
implementations, you can directly refer to field values by their name
since they are in the lexical scope.
Beyond that, the differences between inline ...