This is the mail archive of the kawa@sourceware.org mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]