This is the mail archive of the
kawa@sourceware.org
mailing list for the Kawa project.
Re: case-lambda and Java
On Dec 7, 2009, at 7:02 PM, Per Bothner wrote:
On 12/07/2009 03:48 PM, Jamison Hope wrote:
Is there a way to invoke procedures defined with case-lambda from
Java?
There's the $Mn$Grlist Location which presumably points to the
case-lambda body, but that's all. I was hoping to find either a
family
of overloaded methods (akin to what you get when using #!optional
args),
There is a family of non-public methods: lambda1 ... lambdaN, one for
each "method" of the lambda-case.
or a single $To$List method which performed the dispatch internally.
Nope. What it does is create a GenericProcedure object, and then
dispatch on that depending on argument matching. Using a
GenericProcedure is not optimized well, and may be overkill
for case-lambda, but that is what is happening ...
The $Mn$Grlist field does hold the value of that GenericProc.
In the current SVN it will probably be an Object rather than
a Location - either way you might consider:
(define-constant ->list :: procedure
(case-lambda ...))
Then $Mn$Grlist will have type gnu.mapping.Procedure, which
means you can use Procedure's various apply* methods.
Well, I've now tried this and a few variations, with limited degrees
of success.
When I define ->list like this:
(define-constant ->list :: procedure
(case-lambda ...))
then javap does report $Mn$Grlist as a Procedure
public static final gnu.mapping.Procedure $Mn$Grlist;
but I can't actually use it. In Scheme, if I attempt to compile a file
which does nothing but
(require collections_utils)
-- I'm not even trying to invoke the function yet -- I get a
compilation error:
$ java kawa.repl --target 1.5 --module-static-run --warn-undefined-
variable --main -C usage1.scm
(compiling usage1.scm to usage1)
internal error while compiling usage1.scm
java.lang.ExceptionInInitializerError
at sun.misc.Unsafe.ensureClassInitialized(Native Method)
at
sun
.reflect
.UnsafeFieldAccessorFactory
.newFieldAccessor(UnsafeFieldAccessorFactory.java:25)
at
sun
.reflect.ReflectionFactory.newFieldAccessor(ReflectionFactory.java:
122)
at java.lang.reflect.Field.acquireFieldAccessor(Field.java:918)
at java.lang.reflect.Field.getFieldAccessor(Field.java:899)
at java.lang.reflect.Field.get(Field.java:358)
at gnu.expr.ModuleInfo.setupModuleExp(ModuleInfo.java:167)
at kawa.standard.require.importDefinitions(require.java:292)
at kawa.standard.require.scanForDefinitions(require.java:201)
at kawa.lang.Syntax.scanForm(Syntax.java:65)
at kawa.lang.Translator.scanForm(Translator.java:1054)
at gnu.kawa.lispexpr.LispLanguage.parse(LispLanguage.java:57)
at gnu.expr.Compilation.process(Compilation.java:1858)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:308)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at kawa.repl.compileFiles(repl.java:803)
at kawa.repl.processArgs(repl.java:457)
at kawa.repl.main(repl.java:866)
Caused by: java.lang.NullPointerException
at gnu.expr.GenericProc.add(GenericProc.java:62)
at gnu.expr.GenericProc.setProperties(GenericProc.java:273)
at gnu.expr.GenericProc.make(GenericProc.java:281)
at gnu.kawa.functions.MakeProcedure.applyN(MakeProcedure.java:17)
at collections_utils.<clinit>(collections_utils.scm:46)
... 22 more
collections_utils.scm:46 is the line containing the close-paren for
(define-constant ->list (case-lambda ...)).
From Java, compilation succeeds but I get a runtime error when I try
to call collections_utils.$Mn$Grlist.apply1(new int[]{1,2,3,4,5}):
java.lang.ExceptionInInitializerError
at Usage2.main(Usage2.java:13)
Caused by: java.lang.NullPointerException
at gnu.expr.GenericProc.add(GenericProc.java:62)
at gnu.expr.GenericProc.setProperties(GenericProc.java:273)
at gnu.expr.GenericProc.make(GenericProc.java:281)
at gnu.kawa.functions.MakeProcedure.applyN(MakeProcedure.java:17)
at collections_utils.<clinit>(collections_utils.scm:46)
... 1 more
Scheme also rejects a define-constant without the :: procedure type
declaration, with the same stack trace as the first one above.
If I go back to a regular define instead of define-constant, like
(define ->list :: procedure
(case-lambda ...))
then the call from Java succeeds! Woo hoo!
$ javac Usage2.java
$ java Usage2
(1 2 3 4 5)
but the Scheme usage won't compile:
internal error while compiling usage1.scm
java.lang.NullPointerException
at gnu.expr.ScopeExp.lookup(ScopeExp.java:166)
at kawa.standard.require.importDefinitions(require.java:369)
at kawa.standard.require.scanForDefinitions(require.java:201)
at kawa.lang.Syntax.scanForm(Syntax.java:65)
at kawa.lang.Translator.scanForm(Translator.java:1054)
at gnu.kawa.lispexpr.LispLanguage.parse(LispLanguage.java:57)
at gnu.expr.Compilation.process(Compilation.java:1858)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:308)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at gnu.expr.ModuleInfo.loadByStages(ModuleInfo.java:293)
at kawa.repl.compileFiles(repl.java:803)
at kawa.repl.processArgs(repl.java:457)
at kawa.repl.main(repl.java:866)
Your statement that "$Mn$Grlist field does hold the value of that
GenericProc" led to the only solution I've found which works from both
Scheme and Java: to go back to what I had,
(define ->list
(case-lambda ...))
and call it from Scheme as
(->list ...)
and from Java as
((Procedure)collections_utils.$Mn$Grlist.get()).apply1(...);
which seems terribly clunky on the Java side, but at least it works
without breaking Scheme:
$ cat usage1.scm
(require collections_utils)
(format #t "~A~%" (->list #(1 2 3 4 5)))
$ java usage1
(1 2 3 4 5)
$ cat Usage2.java
public class Usage2 {
public static void main( String[] args ) {
try {
System.out.println( ((gnu.mapping.Procedure)collections_utils.
$Mn$Grlist.get()).apply1
( new int[]{1, 2, 3, 4, 5} ) );
} catch( Throwable e ) {
e.printStackTrace();
}
}
}
$ java Usage2
(1 2 3 4 5)
-Jamie
--
Jamison Hope
The PTR Group
www.theptrgroup.com