case-lambda and Java

Jamison Hope jrh@theptrgroup.com
Mon Dec 7 23:48:00 GMT 2009


Is there a way to invoke procedures defined with case-lambda from  
Java? In a slightly-contrived example, I have written a set of  
functions which convert some Java collection types into Scheme lists,  
along with a case-lambda procedure which dispatches to the others  
based upon argument type:

> $ cat collections_utils.scm
> (module-export Enumeration->list
>                Iterator->list
>                Iterable->list
>                Array->list
>                ->list)
>
> ;;; Returns a list of the elements of the given Enumeration.
> (define (Enumeration->list (enum :: java.util.Enumeration)) :: list
>   (let loop ((ls '()))
>     (if (enum:hasMoreElements)
>         (loop (cons (enum:nextElement) ls))
>         (reverse ls))))
>
> ;;; Returns a list of the elements of the given Iterator.
> (define (Iterator->list (iter :: java.util.Iterator)) :: list
>   (let loop ((ls '()))
>     (if (iter:hasNext)
>         (loop (cons (iter:next) ls))
>         (reverse ls))))
>
> ;;; Returns a list of the elements of the given Iterable.
> (define (Iterable->list (it :: java.lang.Iterable)) :: list
>   (Iterator->list (it:iterator)))
>
> ;;; Returns a list of the elements of the given array.
> (define (Array->list (array :: Object)) :: list
>   (when (*:isArray (array:getClass))
>         (let* ((n :: int (java.lang.reflect.Array:getLength array))
>                (result-vector :: vector (make-vector n)))
>           (do ((i 0 (+ i 1)))
>               ((= i n) (vector->list result-vector))
>             (vector-set! result-vector i (array i))))))
>
> ;;; Converts the given object into a list.
> (define ->list
>   (case-lambda
>    ((l :: list) :: list l)
>    ((l :: java.lang.Iterable) :: list (Iterable->list l))
>    ((l :: java.util.Iterator) :: list (Iterator->list l))
>    ((l :: java.util.Enumeration) :: list (Enumeration->list l))
>    ((l :: Object) :: list (Array->list l))))
> ;;; EOF
> $ java kawa.repl --target 1.5 --module-static-run --warn-undefined- 
> variable -C collections_utils.scm
> (compiling collections_utils.scm to collections_utils)

 From Scheme, I can easily call any of these functions, including - 
 >list:

> $ cat usage1.scm
> (require collections_utils)
>
> (format #t "~A~%" (->list #(1 2 3 4 5)))
> (format #t "~A~%" (Array->list (int[] 1 2 3)))
> ;;; EOF
> $ java kawa.repl --target 1.5 --module-static-run --warn-undefined- 
> variable --main -C usage1.scm
> (compiling usage1.scm to usage1)
> $ java usage1
> (1 2 3 4 5)
> (1 2 3)

but when I inspect collections_utils.class to see what Java methods  
are available to me, I only see analogs of Enumeration->list, Iterator- 
 >list, Iterable->list, and Array->list:
> public class collections_utils extends gnu.expr.ModuleBody{
>     public static final gnu.expr.ModuleMethod Enumeration$Mn$Grlist;
>     public static final gnu.expr.ModuleMethod Iterator$Mn$Grlist;
>     public static final gnu.expr.ModuleMethod Iterable$Mn$Grlist;
>     public static final gnu.expr.ModuleMethod Array$Mn$Grlist;
>     public static final gnu.mapping.Location $Mn$Grlist;
>     public static final collections_utils $instance;
>     public collections_utils();
>     public static gnu.lists.LList Enumeration$To 
> $List(java.util.Enumeration);
>     public static gnu.lists.LList Iterator$To 
> $List(java.util.Iterator);
>     public static gnu.lists.LList Iterable$To 
> $List(java.lang.Iterable);
>     public static gnu.lists.LList Array$To$List(java.lang.Object);
>     public final void run(gnu.mapping.CallContext);
>     public static {};
>     public int match1(gnu.expr.ModuleMethod, java.lang.Object,  
> gnu.mapping.CallContext);
>     public java.lang.Object apply1(gnu.expr.ModuleMethod,  
> java.lang.Object);

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),  
or a single $To$List method which performed the dispatch internally.

So I'm guessing that the answer to my initial question is "No, there's  
no way to invoke procedures defined with case-lambda from Java. Or,  
more accurately, no simple/non-clunky way." Is that correct, or am I  
missing something obvious?

Thanks,
Jamie

--
Jamison Hope
The PTR Group
www.theptrgroup.com





More information about the Kawa mailing list