creating a varargs method with gen-class

310 views
Skip to first unread message

Neale Swinnerton

unread,
May 3, 2012, 5:16:25 AM5/3/12
to clo...@googlegroups.com
Hi,

On SO recently, someone asked how to generate a varargs method with gen-class [1]

i.e how can the equivalent of this method be generated:

    void foo(String... args) { ...}

I did some investigation into a possible answer.

Thinking that varargs methods in java are a trick of the compiler I expected to be able to generate 

     void  foo(String[] args) {...}

with this...

    (ns foo
      (:gen-class
       :name Foo
       :methods [[foo ["[Ljava.lang.String;"] void]]
       ))

and for it to 'just work'(tm). decompiling the generated class I get...

    $ javap -classpath . Foo         
    public class Foo extends java.lang.Object{
        public static {};
        public Foo();
        public java.lang.Object clone();
        public int hashCode();
        public java.lang.String toString();
        public boolean equals(java.lang.Object);
        public void foo(java.lang.String[]);
        public static void main(java.lang.String[]);
    }

The problem is that the foo method is not recognized as a varargs method if you compile against it. 

After some digging I discovered that for a method to be recognized as a varargs, the ACC_VARARGS flag must be on the method in the bytecode.

In the clojure-1.4.0 src  I found that the flag is defined in ./src/jvm/clojure/asm/Opcodes.java  but is never referenced anywhere, which leads me to the conclusion that currently it isn't possible to generate a varargs method in clojure.

Am I missing something?

Should I raise this as an issue on JIRA?



Neale
{t: @sw1nn, w: sw1nn.com }

Neale Swinnerton

unread,
May 3, 2012, 10:56:59 AM5/3/12
to clo...@googlegroups.com
On Thu, May 3, 2012 at 10:16 AM, Neale Swinnerton <ne...@isismanor.com> wrote:

>
> In the clojure-1.4.0 src  I found that the flag is defined in ./src/jvm/clojure/asm/Opcodes.java  but is never referenced anywhere, which leads me to the conclusion that currently it isn't possible to generate a varargs method in clojure.
>
> Am I missing something?
>
> Should I raise this as an issue on JIRA?
>
>

Following on from my earlier e-mail

I had a further tinker around with the clojure src. The attached small
patch against clojure-1.4.0 adds the ability to make a gen-class
method a varargs methodd

e.g with the patch you add some meta data to make the method a varargs
method like this.

(ns foo
(:gen-class
:name Foo
:methods [^:varargs [foo ["[Ljava.lang.String;"] void]]
))

Most of the work to actually do that is already there in the generator
, it's just a question of hooking it up in genclass.clj

I'd be interested in feedback on this. In particular it feels to me
that there should be some extra validation, such that gen-class
complains is you attempt to make a method a varargs method without the
necessary signature.


regards
add-varargs-support-to-gen-class-v0.diff

Snuggy

unread,
May 3, 2012, 12:36:20 PM5/3/12
to clo...@googlegroups.com
Great patch to allow access to this functionality. However, to my eye it looks kinda messy to do something so 'normal'. How difficult would it be to implement some syntactic sugar to "do the right thing" (add the appropriate metadata and massage the type of the final arg):

    (ns foo 
      (:gen-class 
       :name Foo 
       :methods [ [foo [& String] void]] 
       ))  

Using '&' would be consistent with Clojure's syntax but I would imagine it would need to be 'allowed' on the function definition as well to keep things tidy:

   (defn -foo [& string-array] (...))

Maybe this would work anyway without the '&'?

Neale Swinnerton

unread,
May 3, 2012, 1:31:29 PM5/3/12
to clo...@googlegroups.com
Updated patch to support varargs in constructors.

> e.g with the patch you add some meta data to make the method a varargs
> method like this.
>

(ns foo
(:gen-class
:name Foo
:init init
:constructors {^:varargs ["[Ljava.lang.String;"] []}
:methods [^:varargs [foo ["[Ljava.lang.String;"] void]])
)


add-varargs-support-to-gen-class-v1.diff

Daniel Kwiecinski

unread,
Aug 16, 2013, 7:59:19 AM8/16/13
to clo...@googlegroups.com
This is a great patch. Have you submitted it in clojure jira?

--
Lambder

Neale Swinnerton

unread,
Aug 16, 2013, 9:25:56 AM8/16/13
to clo...@googlegroups.com
On 16 August 2013 12:59, Daniel Kwiecinski <daniel.k...@gmail.com> wrote:
This is a great patch. Have you submitted it in clojure jira?

I haven't submitted it. 

I've come to the conclusion that generating complex classes using (:gen-class) is a waste of time. Presumably the primary use case for generating complex java classes is for it to serve as some sort of API endpoint to your system that hides the clojure behind the curtain.

But for the java class to be useful as an api to your system, you want javadocs and an actual file that developers can open in the IDE of their choice.

For background, Rich Hickey gave an impromptu talk about this at the Clojure eXchange in london last year[1]. Essentially his advice was to write a java shim that calls the clojure instead of getting into contortions to do this with :gen-class. This is how it's done in datomic.

It's pretty straightforward to write such a shim. Having said that there are now libraries that make calling clojure from java easier. e.g. Look at @mikera's clojure-utils lib[2]. 

 
 

Daniel Kwiecinski

unread,
Aug 16, 2013, 11:28:09 AM8/16/13
to clo...@googlegroups.com
Sure I understand this. But I have need to generate hundreds of methods in single class. In clojure it is just few lines. Basically I use clojure in this case as an interface to asm lib. 
Also I was thinking about using the varargs not only in gen-class but in feify as well, which generates implementations of interfaces at runtime. Shim wouldn't help here.

--
Lambder

Daniel Kwiecinski

unread,
Sep 11, 2013, 6:02:45 AM9/11/13
to clo...@googlegroups.com
Hi,

   I really badly need this patch in one of my project. But rather than patching clojure's genclass.clj I implemented external utility generating the class with varargs using your patch. 
I'd like to publish it as an open-source micro utility. I know that you'd just added additional meta info but nevertheless you have spend some time on it and if you agree I'd like add your name in credits note. Could you please email me what info you'd like to share?

--
Daniel 


On Friday, 16 August 2013 14:25:56 UTC+1, sw1nn wrote:
Reply all
Reply to author
Forward
0 new messages