(define-class)


Fitting in with Java


Calling Scheme from Java

The jscheme.JS (for Java - Scheme Interface) provides a simple API for invoking Scheme code from Java.

Loading Scheme code:

  JS.load("elf/basic.scm");

Invoking a procedure:

  System.out.println(JS.call("+", JS.toObject(2), JS.toObject(3)));

Eval:

  output.setText(JS.eval(input.getText()).toString());

Wrapper Classes

A Wrapper class is a Java class that invokes Scheme procedures.

JScheme provides Applet and Servlet wrappers.

Listener interface implements 35 Swing listeners.

Example: Comparator:

import java.util.Comparator;
import jsint.Procedure;
import jscheme.JS;

public class Compare1 implements Comparator {
  private Procedure predicate;

  public Compare1(Procedure predicate) {
    this.predicate = predicate;
  }

  private boolean p(Object a, Object b) {
    return JS.booleanValue(JS.call(this.predicate, a, b));
  }

  public int compare(Object a, Object b) {
    return p(a, b) ? -1 : p(b, a) ? 1 : 0;
  }
}

Sorting an array:

> (let ((a #(5 2 1 3 9 6 2 7 1)))
    (Arrays.sort a (Compare1. <))
    a)
#(1 1 2 2 3 5 6 7 9)

Proxy classes

In JDK 1.3 you can generate proxy classes on the fly that implement several interaces.

The proxy calls an InvocagtionHandler to handle each method invocation.

package elf;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import jsint.Procedure;
import jscheme.JS;

public class SchemeInvocationHandler implements InvocationHandler {

  Procedure proc;

  public SchemeInvocationHandler(Procedure proc) { this.proc = proc; }

  public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
    return JS.call(proc, proxy, method, args);
  }
}

Tracing a Java object


(import "elf.SchemeInvocationHandler")
(define (delegate-to delegate handler)
  ;; Returns a proxy that delegates all its interface methods through handler
  ;; to delegate.  See (trace-object) for example.
(Proxy.newProxyInstance
   (.getClassLoader (.getClass delegate))
   (.getInterfaces (.getClass delegate))
   (SchemeInvocationHandler.
    (lambda (proxy method argv)
      (handler delegate method argv)))))

(define (trace-handler delegate method argv)
  (print (list 'call: delegate (.getName method) argv))
  (let ((result (.invoke method delegate argv)))
    (print (list 'return: result))
    result))

(define (trace-object x)
  ;; Returns a proxy object for x that traces all interface methods.
  (delegate-to x trace-handler))


Tracing a Hashtable.

> (define h (Hashtable. 10))
{}
> (define th (trace-object h))
(call: {} "toString" #null)
(return: "{}")
{}
> (.put th 'a 3)
(call: {} "put" #(a 3))
(return: #null)
#null
> (.put th 'b 4)
(call: {a=3} "put" #(b 4))
(return: #null)
#null
> th
(call: {b=4, a=3} "toString" #null)
(return: "{b=4, a=3}")
{b=4, a=3}


Java classes written in Scheme

The macro (define-class) defines a Java class using a syntax that blends Java and Scheme together.

  (define-class
    (package frog)
    (import java.util.Comparator)
    (public class Compare implements Comparator)
    ;; Design issue, fields must be public for Jscheme code to access.

    (public Procedure predicate)	

    (public Compare (Procedure predicate)
     (.predicate$ this predicate))

    (public boolean predicate (Object a Object b)
     ((.predicate$ this) a b))

    (public int compare (Object a Object b)
     (cond ((.predicate this a b) -1)
	   ((.predicate this b a) 1)
	   (else 0)))

    (public boolean equals (Object that)
     (and (eq? (.getClass this) (.getClass that))
	  (eq? (.predicate$ this) (.predicate$ that))))

    (public int hashCode () 0))

Issues

Fields must be declared public for Scheme to access them in an applet.

Fields accessed using reflector syntax

(this ...) and (super ...) in a constructor is treated specially.

(.method super ...): super treated as a special word. No way to invoke super in Reflection API. Scheme must generate a method.

No debugging support.

Allowing internal (define...) might provide a nice modularity mechanism.

How to avoid unnecessary recompilation.