On Sat, Jan 9, 2010 at 2:17 AM, Axel Rauschmayer axel@rauschma.de wrote:
It is dubious whether enhancing the compiler to eliminate reflection for some jcall invocations would be worth the effort. Since Java objects are boxed in ABCL, the compiler would need to generate code to unbox the arguments and box the return value, and place appropriate exception handlers. This would likely increase the size and complexity of the generated code quite a lot. Also, I believe that to optimize a significant number of jcall invocations we need type inference, and that's not an easy task. Of course, the implementation of jcall has to do the very same boxing/unboxing, besides the reflective call itself; it is inevitably less efficient. But I think that, unless your code is made mostly of calls to Java methods, the difference is tolerable.
Naively (=not knowing how it all fits into the bigger ABCL picture), I would expect Java objects not to be boxed and the compiler to be helped by some kind of foreign function declaration. That is, all types are declared statically, dynamic single dispatch should be handled by the JVM. This would mean an initial point of pain (writing the declarations), but elegant usage afterwards. A small script should be able to generate this kind of declarations.
(defjvar foo java.util.StringBuilder) (defjfun sb-to-string java.util.StringBuilder)
(setf foo (new java.util.StringBuilder)) (sb-to-string foo)
Am I making sense or is this off the mark?
The main reason for boxing Java objects is probably to ensure that ABCL can deal with all objects through a common interface - the base class LispObject. Had not this been the case, the methods in most classes in the Java part of ABCL would have had to accept arbitrary Objects and do type checks at runtime:
LispObject type; if(parameter instanceof LispObject) { type = ((LispObject) parameter).typeOf(); } else { type = Symbol.JAVA_OBJECT; }
which would have been ugly and inefficient.
That said, it would be possible for the compiler to avoid some of the boxing/unboxing in certain cases, perhaps with the help of declarations.
The good thing is that any kind of Java calls are always going to be encapsulated inside a lisp interface, so that migrating to something different later is never an issue. I have a feeling that supporting Java's collection APIs (including iterators and Iterable) and Java's streams would be helpful when connecting from ABCL, but I'll have to work some more on my ABCL API for Sesame [1], to be sure.
wrt. streams, the machinery is pretty much already there - ABCL stream classes are wrappers around Java streams and reader/writers. There's currently no way to access that from Lisp except manually instantianting ABCL's stream classes with the Java FFI. One possibility is to add the capability to automatically translate streams returned from Java, like it already happens with strings and numbers; I have code to do that somewhere, an abandoned experiment. My only concern is efficiency: streams are going to be translated (boxed) even if not used as Lisp streams, and unboxed when passed again to Java, and this operation is heavier than usual because ABCL's streams are not mere boxes, they have some initialization logic. An alternative would be to provide operators to do the conversion manually, e.g. (as-lisp-stream java-stream). Then the burden would be on the programmer, but the translation would only be performed when needed.
Bye, Alessio