generated class with overloaded methods

457 views
Skip to first unread message

Craig McDaniel

unread,
Feb 12, 2009, 4:54:59 PM2/12/09
to Clojure
For the benefit of others, since this took me a while to understand...

When using gen-class to extend or implement a superclass with
overloaded methods, use a single multi-arity function to override the
overloaded methods in the superclass:

expmeth/ClassA.java:
package expmeth;
public class ClassA {
public void hello() {
System.err.println("hello from Java!");
}
public void hello(int x) {
System.err.println("hello from Java " + x);
}
}

expmeth/TestMe.clj:
(ns expmeth.TestMe
(:gen-class
:extends expmeth.ClassA
:exposes-methods {hello helloSuper}))
(defn -hello
([this]
(.helloSuper this)
(println "hello from clojure!"))
([this x]
(.helloSuper this x)
(println "hello from clojure..." x)))

testing:
(.hello (expmeth.TestMe.) 17)
(.hello (expmeth.TestMe.) )

Laurent PETIT

unread,
Feb 12, 2009, 6:12:41 PM2/12/09
to clo...@googlegroups.com
Hello,

Thanks for having shared that,

Do you know if there's a way to overload methods with the same arity, then ?

I'm thinking about .read(char ) .read(byte ) .read(String ) .read(Integer ) ... for example,  ?


--
Laurent

2009/2/12 Craig McDaniel <crai...@gmail.com>

Stuart Sierra

unread,
Feb 12, 2009, 10:22:47 PM2/12/09
to Clojure
On Feb 12, 6:12 pm, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> Do you know if there's a way to overload methods with the same arity, then ?
>
> I'm thinking about .read(char ) .read(byte ) .read(String ) .read(Integer )
> ... for example,  ?

I think they're all the same method, from the Clojure point of view.
If you want different behavior, you have to check the type in your
function or use a multimethod.

-Stuart Sierra

Christophe Grand

unread,
Feb 13, 2009, 8:50:46 AM2/13/09
to clo...@googlegroups.com
Laurent PETIT a écrit :

> Hello,
>
> Thanks for having shared that,
>
> Do you know if there's a way to overload methods with the same arity,
> then ?
>
> I'm thinking about .read(char ) .read(byte ) .read(String )
> .read(Integer ) ... for example, ?
Create functions named -read-char -read-byte -read-String -read-Integer.

Christophe


--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.blogspot.com/ (en)


Laurent PETIT

unread,
Feb 13, 2009, 9:03:53 AM2/13/09
to clo...@googlegroups.com

2009/2/13 Christophe Grand <chris...@cgrand.net>


Laurent PETIT a écrit :
> Hello,
>
> Thanks for having shared that,
>
> Do you know if there's a way to overload methods with the same arity,
> then ?
>
> I'm thinking about .read(char ) .read(byte ) .read(String )
> .read(Integer ) ... for example,  ?
Create functions named -read-char -read-byte -read-String -read-Integer.


Is it documented ?
 

Craig McDaniel

unread,
Feb 13, 2009, 9:30:52 AM2/13/09
to Clojure
I just tried it out to be sure. Overloaded methods with the same arity
work as expected. Clojure picks the right method to call via
reflection.

package expmeth;
public class ClassA {
public void hello() {
System.err.println("hello from Java!");
}
public void hello(int x) {
System.err.println("hello from Java. int: " + x);
}
public void hello(String x) {
System.err.println("hello from Java. string: " + x);

Christophe Grand

unread,
Feb 13, 2009, 9:36:26 AM2/13/09
to clo...@googlegroups.com
Laurent PETIT a écrit :
> 2009/2/13 Christophe Grand <chris...@cgrand.net
> <mailto:chris...@cgrand.net>>

>
>
> Laurent PETIT a écrit :
> > Hello,
> >
> > Thanks for having shared that,
> >
> > Do you know if there's a way to overload methods with the same
> arity,
> > then ?
> >
> > I'm thinking about .read(char ) .read(byte ) .read(String )
> > .read(Integer ) ... for example, ?
> Create functions named -read-char -read-byte -read-String
> -read-Integer.
>
>
>
> Is it documented ?

I can't find a reference to it.

The documentation says:
At runtime, a call to some method foo of the generated class will find
the current value of the var implementing.namespace/prefixfoo and call it.

The truth is that a call to some method foo will first try to find the
current value of the var
implementing.namespace/prefixfoo-arg1SimpleTypeName-arg2SimpleTypeName-...
(or implementing.namespace/prefixfoo-void if no args) and if this
current value is null, it will fallback to implementing.namespace/prefixfoo.

Christophe

Laurent PETIT

unread,
Feb 13, 2009, 9:35:44 AM2/13/09
to clo...@googlegroups.com
???

2009/2/13 Craig McDaniel <crai...@gmail.com>

Craig McDaniel

unread,
Feb 13, 2009, 9:44:29 AM2/13/09
to Clojure
Christophe, you're right. I tried it and that method also works. I
didn't know about that secret feature.

(ns expmeth.TestMe
(:gen-class
:extends expmeth.ClassA
:exposes-methods {hello helloSuper}))

(defn -hello [this]
(.helloSuper this)
(println "hello from clojure!"))

(defn -hello-String [this x]
(.helloSuper this x)
(println "hello-String from clojure" x))

(defn -hello-int [this x]
(.helloSuper this x)
(println "hello-int from clojure..." x))

Laurent PETIT

unread,
Feb 13, 2009, 9:56:09 AM2/13/09
to clo...@googlegroups.com
Thanks Christophe, that's the answer I was hoping to get,

If I was twenty years younger, I would just say Clojure roxxXXooRR :-)

(well, I think this is supposed to say that clojure is really cool, hope I didn't misunderstood the rooxxXXooRR "thing" :-)
--
Laurent

2009/2/13 Christophe Grand <chris...@cgrand.net>

Laurent PETIT

unread,
Feb 13, 2009, 9:59:25 AM2/13/09
to clo...@googlegroups.com
Hello ,

Your example code below is not complete (where's helloSuper definition ?), but I think it does not answer my specific question ?

Anyway, it seems that Christophe found the answer.

But I don't know if we should use this knowledge, since it is not exposed as an API ?

--
Laurent

2009/2/13 Craig McDaniel <crai...@gmail.com>

Craig McDaniel

unread,
Feb 13, 2009, 10:25:56 AM2/13/09
to Clojure
On Feb 13, 9:59 am, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> Your example code below is not complete (where's helloSuper definition ?),

Yes, it is complete. See :exposes-methods under (doc gen-class).
"helloSuper" is the exposed name for the hello method in the
superclass. Clojure creates that method for you.

-Craig

Laurent PETIT

unread,
Feb 13, 2009, 10:33:37 AM2/13/09
to clo...@googlegroups.com
Didn't know, thank you again for this knowledge,

--
laurent

2009/2/13 Craig McDaniel <crai...@gmail.com>

Craig McDaniel

unread,
Feb 13, 2009, 10:41:21 AM2/13/09
to Clojure
Both my method (multi-arity) and Christophe's method (overridden
method names contain arguments) do work. I tested them both with the
code posted.

-Craig

Laurent PETIT

unread,
Feb 13, 2009, 10:52:49 AM2/13/09
to clo...@googlegroups.com
Yes, but please note that Christophe's method also solves the problem of defining overloaded methods with different java signatures, but still same name and same arity.

I still can't see how your proposed method solves this particular problem ?

Regards,

--
Laurent

2009/2/13 Craig McDaniel <crai...@gmail.com>

Craig McDaniel

unread,
Feb 13, 2009, 11:47:51 AM2/13/09
to Clojure
I guess I don't understand. In the Clojure code below, the double
arity method does in fact override all three of the methods from the
superclass (two of which have the same name and same arity). Isn't
that what you're looking for? Try it out.

|-- build.xml
|-- go.clj
|-- src
| `-- expmeth
| |-- ClassA.java
| `-- TestMe.clj

$ cat src/expmeth/ClassA.java
package expmeth;

public class ClassA {
public void hello() {
System.err.println("hello from Java!");
}
public void hello(int x) {
System.err.println("hello from Java. int: " + x);
}
public void hello(String x) {
System.err.println("hello from Java. string: " + x);
}
}

$ cat src/expmeth/TestMe.clj
(ns expmeth.TestMe
(:gen-class
:extends expmeth.ClassA
:exposes-methods {hello helloSuper}))

(defn -hello
([this]
(.helloSuper this)
(println "hello from clojure!"))
([this x]
(.helloSuper this x)
(println "hello from clojure..." x)))

$ cat go.clj
(import '(expmeth TestMe))
(.hello (TestMe.))
(.hello (TestMe.) 7)
(.hello (TestMe.) "woo")

$ cat build.xml
<project name="expmeth" default="jar" basedir=".">
<property name="src.home" location="src"/>
<property name="build.home" location="build"/>
<property name="jarfile" location="expmeth.jar"/>

<available property="hasclojure" file="${clojure.jar}"/>

<path id="compile.classpath">
</path>

<target name="init">
<mkdir dir="${build.home}"/>
</target>

<target name="compile" depends="init">
<javac srcdir="${src.home}" destdir="${build.home}" debug="on"
includes="**/*.java" deprecation="on" target="1.5"
source="1.5">
<classpath refid="compile.classpath"/>
<compilerarg line="-Xlint:-path"/>
</javac>
</target>

<target name="compile-clojure" depends="compile">
<java classname="clojure.lang.Compile">
<classpath>
<pathelement location="${build.home}"/>
<pathelement location="${src.home}"/>
<path location="${clojure.jar}"/>
</classpath>
<sysproperty key="clojure.compile.path" value="${build.home}"/>
<arg value="expmeth.TestMe"/>
</java>
</target>

<target name="jar" depends="compile-clojure">
<jar jarfile="${jarfile}">
<fileset dir="${src.home}" includes="**/*.clj"/>
<fileset dir="${build.home}" includes="**/*.class"/>
</jar>
</target>

<target name="clean" description="cleanup">
<delete dir="${build.home}"/>
<delete file="${jarfile}"/>
</target>

</project>

$ ant

$ java -cp build:/home/kreg/src/clojure/clojure.jar clojure.main
go.clj
hello from Java!
hello from clojure!
hello from Java. int: 7
hello from clojure... 7
hello from Java. string: woo
hello from clojure... woo

Laurent PETIT

unread,
Feb 13, 2009, 12:04:45 PM2/13/09
to clo...@googlegroups.com
Hello,

The code you provided works well.

But still, I insist, it has nothing to do with how to solve the problem of how one can overload methods with same name, same arity, but different types in the signature.

You only demonstrated that clojure handles well the dispatching of method calls based on dynamic reflection on the types of the arguments, even in the case of an automatically generated method such as helloSuper.

--
Laurent


2009/2/13 Craig McDaniel <crai...@gmail.com>

Craig McDaniel

unread,
Feb 13, 2009, 12:53:25 PM2/13/09
to Clojure
OK, I understand. When you want separate Clojure functions that
execute different code for same arity/different signature case, you
must use the method demonstrated by Christophe. The code I showed was
only useful when you don't care about the type. You could use the
multi-arity function and manually check the type of the argument
inside the function--as Stuart mentioned earlier in the thread, but
that's not as clean as Christophe's example.

-Craig
Reply all
Reply to author
Forward
0 new messages