Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

A record can implement protocols. However, each time I think of a new function that I would like the record to implement, I have to add it to an existing protocol or create a new protocol. How do I get around this? Ideally, I'd just like to associate a function to a record without having to define a protocol.

share|improve this question
add comment

2 Answers

Then just write a function that takes an instance of that record as an argument.

defrecord doesn't "implement" a protocol, in the sense that class in a Java-like OO language implements an interface. What it does is define a datatype, and give you some syntactic sugar to implement a protocol that operates on that datatype. There's a pretty great overview of just what sort of problem protocols are meant to solve here - http://www.ibm.com/developerworks/library/j-clojure-protocols/

share|improve this answer
add comment

Excellent question. Here's an answer based on a similar one I gave on StackOverflow.

As usual, there's a beautiful way to do things in Clojure - here's how to implement your own simple dynamic OO system (including inheritance, polymorphism and encapsulation) in 10 lines of Clojure.

The idea: You can put functions inside normals Clojure maps or records if you want, creating an OO-like structure. You can then use this in a "prototype" style.

; define a prototype instance to serve as your "class"
; use this to define your methods, plus any default values
(def person-class
  {:get-full-name 
    (fn [this] (str (:first-name this) " " (:last-name this)))})

; define an instance by merging member variables into the class
(def john 
  (merge person-class 
    {:first-name "John" :last-name "Smith"}))

; macro for calling a method - don't really need it but makes code cleaner
(defmacro call [this method & xs]
  `(let [this# ~this] ((~method this#) this# ~@xs)))

; call the "method"
(call john :get-full-name)
=> "John Smith"

; added bonus - inheritance for free!
(def mary (merge john {:first-name "Mary"}))
(call mary :get-full-name)
=> "Mary Smith"
share|improve this answer
    
hmm just realised I've posted the same answer to the same poster on both StackOverflow and Programmers..... ah well, guess that both sites have audiences that would be interested! –  mikera Feb 17 '11 at 11:19
    
See also github.com/Prismatic/eng-practices/blob/master/clojure/… for an in depth discussion of the topic including the desugared version of the call macro syntax from mikera's answer. –  John Nov 30 '13 at 11:46
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.