Partial support for JDK 1.5 vararg methods in BeansWrapper

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Partial support for JDK 1.5 vararg methods in BeansWrapper

Attila Szegedi
Hi folks,

today I committed to SVN a partial support for JDK 1.5 vararg methods and  
constructors in BeansWrapper for FreeMarker 2.4. "Partial" in this context  
means it works if the public vararg method's name is not publicly  
overloaded (alternatively, if the vararg constructor is the sole public  
constructor). Figuring out the right method to invoke for overloaded ones  
promises to be quite challenging - I'm going to nail down that issue too,  
but it takes a bit more overhauling of FreeMarker's overloaded method  
resolution logic, so I wanted to commit the easier version as a baseline  
to hack further from...

Attila.

--
home: http://www.szegedi.org
weblog: http://constc.blogspot.com

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Reply | Threaded
Open this post in threaded view
|

Re: Partial support for JDK 1.5 vararg methods in BeansWrapper

Attila Szegedi
Following up, until I figure out what to do with overloaded methods, I  
added two other features that'll make use of overloaded varargs methods  
more convenient, even if not fully transparent:

1. If an array of expected type is passed as the last argument to the  
vararg method, it is used as varargs.
2. BeansWrapper can now unwrap arbitrary TemplateSequenceModel to a native  
Java array when trying to match it to a formal method argument declared as  
array.

This means that if you have a vararg Java method

public void foo(String s, int... i)
{
     // do something
}

You can invoke it from the template as either

bean.foo("blah", 1, 2, 3)

or

bean.foo("blah", [1, 2, 3]);

That's because BeansWrapper will convert the sequence literal into Java  
int[] (which has to be done anyway in order to invoke varargs methods --  
they're just Java compile time syntactic sugar,  
java.lang.reflect.Method#invoke() still expects you to create an array  
just as if the method was declared "foo(String s, int[] i)").

You have this choice in case the method is *not* overloaded. In case it  
*is* overloaded, you can only use the second variant - until I figure out  
a way to make it syntactically transparent (assuming it is possible at all  
-- remember, we're working from a dynamically typed language here, we  
don't have all information at our disposal that a Java compiler does).

Attila.

--
home: http://www.szegedi.org
weblog: http://constc.blogspot.com

On Thu, 21 Dec 2006 10:10:17 +0100, Attila Szegedi <[hidden email]>  
wrote:

> Hi folks,
>
> today I committed to SVN a partial support for JDK 1.5 vararg methods and
> constructors in BeansWrapper for FreeMarker 2.4. "Partial" in this  
> context
> means it works if the public vararg method's name is not publicly
> overloaded (alternatively, if the vararg constructor is the sole public
> constructor). Figuring out the right method to invoke for overloaded ones
> promises to be quite challenging - I'm going to nail down that issue too,
> but it takes a bit more overhauling of FreeMarker's overloaded method
> resolution logic, so I wanted to commit the easier version as a baseline
> to hack further from...
>
> Attila.

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Reply | Threaded
Open this post in threaded view
|

Re: Partial support for JDK 1.5 vararg methods in BeansWrapper

Daniel Dekany
Thursday, December 21, 2006, 11:17:54 AM, Attila Szegedi wrote:


> Following up, until I figure out what to do with overloaded methods, I
> added two other features that'll make use of overloaded varargs methods
> more convenient, even if not fully transparent:
>
> 1. If an array of expected type is passed as the last argument to the
> vararg method, it is used as varargs.
> 2. BeansWrapper can now unwrap arbitrary TemplateSequenceModel to a native
> Java array when trying to match it to a formal method argument declared as
> array.
>
> This means that if you have a vararg Java method
>
> public void foo(String s, int... i)
> {
>      // do something
> }
>
> You can invoke it from the template as either
>
> bean.foo("blah", 1, 2, 3)
>
> or
>
> bean.foo("blah", [1, 2, 3]);

Um... I don't know the Java 1.5 vararg feature too much, but my
feeling is that this last variation doesn't make sense. Because, from
the side of the caller a vararg is not like an array. That's how the
internal implementation of the methods see varargs, and the low level
API-s... but those are just technical details that the caller
shouldn't care about too much. Other than that, this approach adds an
extra ambiguity to the mix... is [1, 2, 3] the 2nd parameter itself,
or 2nd + 3rd + 4th parameter? Now of course you can be smart and can
say that if there are no overloads then there is no ambiguity etc, and
this would well fit into your tendency of being overly smart/clever.
It's almost always a bad idea to be very clever when you design the
"public interface" of something, because you will confuse users. Magic
makes it hard to predict what will happen.

> That's because BeansWrapper will convert the sequence literal into
> Java int[] (which has to be done anyway in order to invoke varargs
> methods -- they're just Java compile time syntactic sugar,
> java.lang.reflect.Method#invoke() still expects you to create an
> array just as if the method was declared "foo(String s, int[] i)").

That's what I'm talking about... you know too much. :) "just" syntax?
Well it allows for the *caller* to specify a variable number of
arguments. Not an array, but genuine variable number of arguments.
Like if you had an infinite set of overloads, foo(Strong, int),
foo(Strong, int, int), foo(Strong, int, int, int), etc. (You might as
well could use this approach for the wrapper?) Whatever they managed
to done in the case of the Java platform, I don't know, but it is the
intent. On the method implementation side, you obviously can't give
names for each argument if the number of arguments is not known until
execution time, so the language must present that part of the argument
list to you (the programmer) as an array or something like that, no
mater if it is really implemented as an array or was just pushed into
the stack like normal arguments are. And the technical fact that they
have solved it with array on the JVM level is yet another thing, and
is totally irrelevant now.

> You have this choice in case the method is *not* overloaded. In case it
> *is* overloaded, you can only use the second variant - until I figure out
> a way to make it syntactically transparent (assuming it is possible at all
> -- remember, we're working from a dynamically typed language here, we
> don't have all information at our disposal that a Java compiler does).

What relevant information we don't have on runtime?

> Attila.

--
Best regards,
 Daniel Dekany


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Reply | Threaded
Open this post in threaded view
|

Re: Partial support for JDK 1.5 vararg methods in BeansWrapper

Attila Szegedi
On Thu, 21 Dec 2006 12:28:47 +0100, Daniel Dekany <[hidden email]>  
wrote:

>
> That's what I'm talking about... you know too much. :) "just" syntax?
> Well it allows for the *caller* to specify a variable number of
> arguments. Not an array, but genuine variable number of arguments.
> Like if you had an infinite set of overloads, foo(Strong, int),
> foo(Strong, int, int), foo(Strong, int, int, int), etc. (You might as
> well could use this approach for the wrapper?) Whatever they managed
> to done in the case of the Java platform, I don't know, but it is the
> intent. On the method implementation side, you obviously can't give
> names for each argument if the number of arguments is not known until
> execution time, so the language must present that part of the argument
> list to you (the programmer) as an array or something like that, no
> mater if it is really implemented as an array or was just pushed into
> the stack like normal arguments are. And the technical fact that they
> have solved it with array on the JVM level is yet another thing, and
> is totally irrelevant now.

Well, I'll have to disagree. The JVM spec didn't change at all for this.  
All the trickery is done by the compiler. In the .class file, the vararg  
method will have an array as its last argument. If you examine the method  
through reflection, i.e. you call "method.getArgumentTypes()" for a method  
declared as "foo(String a, int... i)" you'll get back "String.class,  
int[].class". And when invoking a vararg method through reflection, you  
must pack the extra arguments manually into an array, and pass it as the  
last argument. That is, you can't just do

fooMethod.invoke(bean, new Object[] { "blah", new Integer(1), new  
Integer(2) })

but must instead do:

fooMethod.invoke(bean, new Object[] { "blah", new int[] { 1, 2 });

instead. Anyway -- I'm thinking about how to smarten the BeansWrapper to  
cope with vararg overloaded methods as well - once I figure out, I'll tell  
you :-) As a matter of fact, I'm now reading the *thoroughly* rewritten  
section 15.12 of JLS titled "Method Invocation Expressions", and its  
starting to clear up.

>
> What relevant information we don't have on runtime?
>

Actually, I've been thinking it further, and I think we probably have  
every information we need.

Attila.

--
home: http://www.szegedi.org
weblog: http://constc.blogspot.com

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Reply | Threaded
Open this post in threaded view
|

Re: Partial support for JDK 1.5 vararg methods in BeansWrapper

Daniel Dekany
Thursday, December 21, 2006, 7:42:38 PM, Attila Szegedi wrote:


> On Thu, 21 Dec 2006 12:28:47 +0100, Daniel Dekany <[hidden email]>
> wrote:
>
>>
>> That's what I'm talking about... you know too much. :) "just" syntax?
>> Well it allows for the *caller* to specify a variable number of
>> arguments. Not an array, but genuine variable number of arguments.
>> Like if you had an infinite set of overloads, foo(Strong, int),
>> foo(Strong, int, int), foo(Strong, int, int, int), etc. (You might as
>> well could use this approach for the wrapper?) Whatever they managed
>> to done in the case of the Java platform, I don't know, but it is the
>> intent. On the method implementation side, you obviously can't give
>> names for each argument if the number of arguments is not known until
>> execution time, so the language must present that part of the argument
>> list to you (the programmer) as an array or something like that, no
>> mater if it is really implemented as an array or was just pushed into
>> the stack like normal arguments are. And the technical fact that they
>> have solved it with array on the JVM level is yet another thing, and
>> is totally irrelevant now.
>
> Well, I'll have to disagree.

Errr... /-8

> The JVM spec didn't change at all for this. All the trickery is done
> by the compiler. In the .class file, the vararg method will have an
> array as its last argument. If you examine the method through
> reflection, i.e. you call "method.getArgumentTypes()" for a method
> declared as "foo(String a, int... i)" you'll get back "String.class,
> int[].class". And when invoking a vararg method through reflection,
> you must pack the extra arguments manually into an array, and pass
> it as the last argument. That is, you can't just do
>
> fooMethod.invoke(bean, new Object[] { "blah", new Integer(1), new  
> Integer(2) })
>
> but must instead do:
>
> fooMethod.invoke(bean, new Object[] { "blah", new int[] { 1, 2 });
>
> instead.

I hoped I will be convinced with something relevant, but this is when
I used to say "So what? Who gives a s***!" etc., but I'm more polite
than back then. So, what I tried to tell in my previous mail is
exactly that all of these doesn't mater. These are just low level
things. In all sane languages the intent with varargs should be that
you can pass variable number of arguments. Not an array, but variable
number of arguments. That's its name BTW, "varargs". And I really hope
you can't write both printf("%s%s", "foo", "bar") and printf("%s%s",
new String[]{"foo", "bar"}) in Java Language either. The usage of
arrays on the calleD side and on the low level is a consequence that
should not affect the calleR. I know, if we look at the compiled code,
the caller is affected, but I'm talking about the Java Language, the
source code. The others are just the dirty technical details.

> Anyway -- I'm thinking about how to smarten the BeansWrapper to
> cope with vararg overloaded methods as well - once I figure out, I'll tell
> you :-)

I still wonder why do varargs cause any *theoretical* confusion in the
method selection. A vararg just defines an infinite number of
overloaded methods, as far as I can see. Now, admittedly, I don't know
what did they done in the case of Java Language, but I hope it's not
something utterly artificial...

> As a matter of fact, I'm now reading the *thoroughly* rewritten
> section 15.12 of JLS titled "Method Invocation Expressions", and its  
> starting to clear up.
>
>>
>> What relevant information we don't have on runtime?
>>
>
> Actually, I've been thinking it further, and I think we probably have
> every information we need.

Like, you can differentiate a single parameter that is an array from a
varags using Method.isVarArgs().

> Attila.

--
Best regards,
 Daniel Dekany


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel