ERights Home e 
Back to: ECDAF Startup No Next Sibling

Proxy Typing in New-E
A topical tactical page
By RobJ 19 May 98


Historical Note: New-E was an intermediate step between Original-E and ELib.



New-E has an outstanding design issue that needs to get sorted soon.  This page describes the situation, the issues, and the potential strategies.  We'll pick one once everyone's had a chance to review the situation.

The Situation

Let's assume the following new-E-ish code:
    class Argument implements Proxyable
        String myData;
        Argument(String data) { myData = data; }
        // warning: data better not be null! ...this becomes important later
        void doSomething () { data.print(); }
    }
    ...
        Argument arg = new Argument("yow");
        E.send(someOtherProxy, "someMessage", arg);
    ...
In this code, someOtherProxy is a proxy for some object on the other side of the wire.  This object implements the "someMessage" method.  The argument to the "someMessage" method is the proxyable argument "arg".
When the "someMessage" envelope gets received by the remote machine, the remote machine needs to create a proxy representing the "arg" object.
The question is, what kind of proxy object does that remote machine create?  And how does that interact with how the "someMessage" method needs to be declared?

Generic Proxies

The simplest sort of Proxy object is one which is strictly generic:
    class Proxy {
        int mySwissNumber, myRemoteRegistrarID;
        public int swissNumber () { return mySwissNumber; }
        public int remoteRegistrarID() { return myRemoteRegistrarID; }
        Proxy (int id, int initialNumber) { myRemoteRegistrarID = id; mySwissNumber = number; }
    }
If this were the sort of Proxy used in the new-E comm system, then somewhere in the E runtime (in the implementation of E.send) there would be some code of the form (don't have a heart attack MarkM, I know there is probably a cleaner way to do this):
    if (sendTarget instanceof Proxy) {
        sendEnvelopeToProxy(sendTarget, messageName, arguments);
    }
So let's assume the remote machine's comm system created one of these proxy objects to represent the received "arg" argument.
If the remote machine's "someOtherProxy" object went and did
    E.send(arg, "doSomething");
somewhere in its "someMessage" method, it would call into E.send, which would result in a network "doSomething" message getting sent--because the E.send call, invoked on arg (an instanceof Proxy), would wind up doing sendEnvelopeToProxy.  (Note that at no time do we do "arg.doSomething()" since this is E we're talking about and we know, because we pay attention, that arg might be a remote object.)

However

The question then is, what is the declaration of someMessage?
One would think it would be:
    class SomeClass implements Proxyable { // or else we couldn't have had SomeOtherProxy pointing to this
        void someMessage (Argument arg) {
            E.send(arg, "doSomething");
        }
    }
Since after all, that's what it must be if it takes an argument of type Argument, right?
The problem is that this doesn't work with generic proxies!  If the remote machine created an object of type Proxy (instead of an object of type Argument) to represent the incoming value of "arg", then the E runtime couldn't invoke someMessage, since the "arg" object would in fact not be of type Argument.  You would wind up needing to say
        /*
         * Some message or other.
         * @param arg The only argument (type Argument)
         */
        void someMessage (Proxyable arg) {
            E.send(arg, "doSomething");
        }
That way, the E runtime could still invoke the someMessage method through CRAPI despite the fact that arg is not an Argument.  If you wanted to record that arg should be of type Argument, you would need to do so in the javadoc comments.
If we captured this type info rigorously in the javadoc comments, we could then write a tool which could type-check all of our E sends, ensuring that the known types of the objects being sent matched the javadoc information.

The other possibility

The alternative way to do it is to create some kind of proxy object which has the correct type.  You make the "arg" proxy object actually an instanceof Argument in some way or other.  There are two ways to do it:

El Cheapo (tm 1998 Arturo)

We could make it a requirement of being Proxyable that you implement a special constructor:
    class Proxyable {
        protected Proxy myProxy = null;
    }
    class Argument extends Proxyable {
        String myData;
        Argument(String data) { myData = data; }
        Argument(Proxy proxy) { myProxy = proxy; }
        void doSomething () { if (ProxyChecking.ON && myProxy == null) { data.print(); }}
    }
The idea here is that the code which creates the proxy would do it like so:
    Proxy newProxy = new Proxy(informationFromTheWireAboutTheArgObject);
    Object newTypedProxy = new Argument(newProxy);
This basically creates a "proxy-only" Argument object, with most of its instance variables (except for myProxy) being null.
You could then invoke someMessage passing in newTypedProxy, and it would work with the typed version of someMessage.
The problem would be if you tried to call newTypedProxy.doSomething() directly; the newTypedProxy only has part of the state of the actual Argument object, so you could die horribly.  This is why the doSomething() code above checks that myProxy == null before actually doing its thing; if myProxy != null, this Argument object is actually a proxy with mostly-null state, and would die if it actually tried to doSomething().
So if you do this, you wind up with lots of objects that have the proper Java type information for what they ought to be, but which are huge potential sources of null pointer exceptions if you forget to check whether they're really proxies.

Stub generation

The way RMI and old-E and similar systems solved this issue was by stub generation.  You basically ran a utility over all your Proxyable classes and it spat out new classes automatically:
    class ArgumentProxy implements Argument {
        Proxy myProxy;
        ArgumentProxy (Proxy underlyingProxy) { ... }
        void doSomething () { sendToProxy(myProxy, "doSomething"); }
    }
Or something like that.  You get the idea:  for every proxyable class, you make a new class that has the same interface (glossing over the fact that Argument is a class and not an interface here), and you have its methods do the asynchronous invocation.
The problem with this is that it results in class bloat, and that it requires an additional tool and an additional compile step.

The Big Picture

What this really boils down to is one fundamental choice, and then one sub-choice along each option:
  1. Do we use Java declarations to describe the types of arguments that may have come in over the wire?

  2. If we do not, then we use Proxyable as the Java-declared type of all arguments-that-may-be-proxies.  In this case the two subchoices are:
    1. Do we just leave it at that?

    2. If that were all the typechecking that our compile environment attempted to do, we would be paying no space cost and no time cost for our proxy strategy, but we would have some risk of passing badly typed arguments around; this could result in "bad type" errors down the line when you lose track of what type you thought an argument was.  The compiler would be basically no help at all when tracking types of E message send arguments.  Not only that, but we would have no place in the code to track what those arguments should be, and it would be hugely painful to reconstruct that information later.
    3. Do we create a tool to statically check E message sends against Javadoc type info?

    4. If we had a (religiously used) Javadoc convention for listing the type of a Java-typed-as-Object might-be-a-proxy argument, and if we had a static tool that could analyze that information and typecheck the actual arguments to E sends against it, it wouldn't matter that we didn't have the type information in the Java declaration; the checked Javadoc, with the typechecker, would do the job.  (And in fact it would do an even better job, because it could type-check the sends themselves!--all the discussion we've done so far is just about the received arguments in the receiver, not about catching type problems in E.send itself!)  However, we don't have such a tool, and it would take months to write one (the last estimate was six weeks, with no real investigation of that time estimate).
    If we do use Java declarations to provide type information for over-the-wire objects, the two subchoices are:
    1. Do we do El Cheapo deflectors?

    2. They introduce a substantial risk of misbehavior at runtime, if you get sloppy and start doing things with objects that look like your everyday objects but are actually proxies.  They also introduce some development overhead in that every "real" method needs to check (for safety) that it is not being invoked on a proxy by mistake.  However, there is no tool cost to doing El Cheapo; we could start doing it immediately.
    3. Do we build a stub generator?

    4. This would start moving us back into the tools world, which we've already said we want to get out of.  (It would be substantially simpler than a Javadoc-type-info-checking static typechecker, though!)  One positive of this is that it is upwards compatible with El Cheapo; we could do El Cheapo now and build a stub generator later, and none of our (correct) code would care.
    It's also worth noting that if we keep type information in the Java declarations (i.e. we do El Cheapo or stub generation), we could always later build an E.send typechecker that used that information.
It's a gnarly problem space.  Let me know if some or all of this sounded totally garbled, and stay tuned for the resolution.

 

 
Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
ERights Home e 
Back to: ECDAF Startup No Next Sibling
Download    FAQ    API    Mail Archive    Donate

report bug (including invalid html)

Golden Key Campaign Blue Ribbon Campaign