Hi Jim:

I think the problem is that you are actually calling the *getDistance *protocol 
function with only 2 arguments in the line in bold below:
 
(defrecord LevenshteinDistance [] 
  IDistance 
  (getDistance [_ s1 s2] 
     *(getDistance s1 s2))  ;; <- Calling a getDistance function with 2 args
*
  (getDistance [_ s1 s2 weight] 
     (getDistance s1 s2 weight)))

While in the protocol definition there's only a 3 and 4 arguments 
declarations for getDistance.

(defprotocol IDistance 
  (getDistance 
    [this s1 s2]            ; 3 args
    [this s1 s2 m-weight])) ; 4 args

You could add a 2 arguments override for the *getDistance* protocol 
function and it would work by calling the 2 args implementation added to 
String, which is actually never registered in the protocol and goes 
unnoticed for the reason that follows, which I myself found out while 
experimenting with your code, you can skip it if you like, I just had a 
little fun investigating some Clojure code :).

When using *extend-type*, any implementation for a protocol function with a 
number of args not present in the protocol's declaration doesn't seem to 
produce any errors or warnings (*extend* presents the same behavior, which 
makes sense since *extend-type* uses it).

(defprotocol SomeProtocol
  (some-function [this x] [this x y]))
     
(defrecord SomeRecord [])

(extend-type SomeRecord
  SomeProtocol 
  (some-function 
    ([_] (println "1-arg"))         ; this is not declared 
    ([_ _ _ _ _] (println "5-arg")) ; this is not declared 
    ([_ x y]
      (some-function x y)))

However, a *CompilerException* is thrown when implementing a protocol using 
the *defrecord* macro, and declaring a non-existing override for the 
function. I looked a little bit into the code of *defrecord *and the reason 
for this seems to be that it ultimately uses *deftype* which actually 
creates a class that implements the methods for the Java interface that the 
protocol defines, the compiler checks in this case if there's any method 
with the name and arity with the supplied implementation, and throws an 
exception if it doesn't.

(defprotocol SomeProtocol
  (some-function [this x] [this x y]))

(defrecord SomeRecord []
  SomeProtocol 
  (some-function [_] (println "1-arg")) ; this is not declared 
  (some-function [_ x y] 
    (some-function x y)))

#<CompilerException java.lang.IllegalArgumentException: Can't define method 
not in interfaces: some_function, compiling: (file.clj)>

This seems to indicate that using extend (or extend-type) vs. deftpye (or 
defrecord) for implementing a protocol yields two different results, the 
former registers the function implementations in the protocol using the map 
supplied and the latter actually creates a class method for the record or 
type class generated. 

This was not obvious at all to me and I think I even recall reading 
somewhere (can't remember exactly where and can't find it right now) that 
the defrecord "inline" implementation was just a convenience form for 
extend/extend-type, but is it possible that it's actually more performant 
to use the defrecord/deftpye?

Hope it helps,

Juan

On Thursday, February 14, 2013 5:16:53 PM UTC-3, Jim foo.bar wrote:
>
> let me explain with an example: 
>
>
> ;;in some namespace x 
>
> (defprotocol IStemmable 
> (stem [this token] [this token lang]) 
> (getRoot [this token dictionary])) 
>
> (defprotocol IDistance 
> (getDistance [this s1 s2] [this s1 s2 m-weight])) 
>
> ;;in some namespace y that refers all vars from x 
>
> (extend-type String 
>   IStemmable 
>   (stem 
>    ([this] (stem this "english")) 
>    ([this lang] 
>       (let [stemmer (help/porter-stemmer lang)] 
>          (doto stemmer 
>                  (.setCurrent this) 
>                  (.stem)) 
>            (.getCurrent stemmer)))) 
>   (getRoot [this _ dic] (get dic this "NOT-FOUND!")) 
>   IDistance 
>   (getDistance 
>     ([this other] 
>        (help/levenshtein-distance* this other)) ;;delegate to helper fn 
>     ([this other mismatch-weight] 
>        (help/levenshtein-distance* this other mismatch-weight)))) ;;same 
> here 
>
>
> (defrecord PorterStemmer [lang input output] ;;COMPILES AND WORKS FINE - 
> NO PROBLEMS 
> IStemmable 
> (stem [_ token] 
>    (stem token lang))       ;;delegate to String for this 
> (getRoot [_ token dic] 
>    (getRoot token _ dic)))) ;;delegate to String for this 
>
>
> (defrecord LevenshteinDistance []  ;;DOESN'T COMPILE 
> IDistance 
> (getDistance [_ s1 s2] 
>    (getDistance s1 s2))  ;;delegate to String for this 
> (getDistance [_ s1 s2 weight] 
>    (getDistance s1 s2 weight)))  ;;and this 
>
>
> trying to load the file results in: 
>
> CompilerException java.lang.IllegalArgumentException: No single method: 
> getDistance of interface: cluja.protocols.IDistance found for function: 
> getDistance of protocol: IDistance, 
> compiling:(/media/sorted/uni_stick/cluja/src/cluja/concretions/models.clj:152:3)
>  
>
>
>
> What am I doing wrong? I am practically doing the exact same thing for 
> these 2 protocols. Both of them delegate to the implementations extended 
> to string. I keep looking at the code and I see nothing wrong! The 
> 'getDistance' with 3 args delegates to the one with 2 and the one with 4 
> delegates to the one with 3 (from String)...even more confusingly why 
> one works and the other complains? any ideas/insights? 
>
> Jim 
>
>

-- 
-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to