Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by

There seems to be a problem in trying to define a protocol with a method named "clear"

(defprotocol PClear

 (clear (link: o)))

=> PClear

(defrecord Foo (link: )

   (clear (link: o) o))

=> CompilerException java.lang.ClassFormatError: Duplicate method name&signature in class file xxxx/Foo, compiling:(NO_SOURCE_PATH:1:1)

I assume this is due to a name conflict with the Java method Collection.clear() in the underlying implementation. However the error is very unclear about this, and the potential for conflict appears to be undocumented as far as I can see.

There seem to be two possible approaches to fixing this:
a) Disallow the use of "clear" as a protocol method name (in which case the error should be more informative, and the rule should be documented)
b) Find a way to support this in the class file format (possibly by overloading on JVM return types, since Collection.clear() returns void??)

6 Answers

0 votes

Comment made by: bronsa

Mike, the jvm doesn't support return type overloading so your second suggestion is not technically possible.

Reading the doc for defrecord {quote} The class will have implementations of several (clojure.lang)
interfaces generated automatically: IObj (metadata support) and
IPersistentMap, and all of their superinterfaces.

Perharps java.util.Collection (or even better, java.util.Map) should be mentioned here.

0 votes

Comment made by: alexmiller

I think this should be a doc enhancement request.

0 votes

Comment made by: sohta

It might be out of the scope of this ticket, but protocol method conflicts can cause some other kinds of errors:

user=> (defprotocol P1 (finalize [this]))
user=> (defrecord R1 [] P1 (finalize [this]))

CompilerException java.lang.VerifyError: (class: user/R1, method: finalize signature: ()Ljava/lang/Object;) Unable to pop operand off an empty stack, compiling: ...
user=> (defprotocol P2 (wait [this]))
user=> (defrecord R2 [] P2 (wait [this]))
user=> (def r (->R2))


user=> (wait r)
CompilerException java.lang.IllegalArgumentException: No single method: wait of interface: user.P2 found for function: wait of protocol: P2, compiling: ...

IMHO it would be nicer if defprotocol would warn method conflicts with a more informative message.

0 votes

Comment made by: mikera

@Nicola Mometto : I believe the JVM does in fact support return type overloading:

"Note that there may be more than one matching method in a class because while the Java language forbids a class to declare multiple methods with the same signature but different return types, the Java virtual machine does not. This increased flexibility in the virtual machine can be used to implement various language features. For example, covariant returns can be implemented with bridge methods; the bridge method and the method being overridden would have the same signature but different return types."

See : http://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getMethod-java.lang.String-java.lang.Class...-

0 votes

Comment made by: bronsa

Ah, yes of course, thanks.

0 votes
Reference: https://clojure.atlassian.net/browse/CLJ-1791 (reported by mikera)