[E-Lang] Reliance & Static Security Checking

Mark S. Miller markm@caplet.com
Thu, 04 Jan 2001 21:05:25 -0800


At 06:15 PM Thursday 1/4/01, Bill Frantz wrote:
>There is a limit to what the compiler can do.  I can imagine stack and
>queue objects, each of which implement only push and pop methods.  The
>compiler might very well say they are the same interface, not being able to
>read the differences described only in the comments.  I expect programmers
>will not consider them to be interchangeable.

An excellent example.  Stack and Queue may very well have the same 
signature, but they have different type *names*, which correspond to 
differently commented type declaration source text and Javadoc URLs.  
Adopting Java's static checking rules for the moment, if implementation Foo 
is accepted by the Java static checker when declared:

    class Foo implements Stack { ... }

then it would also be accepted by the static checker when declared

    class Foo implements Queue { ... }

Therefore Foo's programmer is getting the static checker to do the same 
work for him in either case.  Let's call this "enforced correctness".  So if 
the enforced correctness checks are the same, why would Foo's programmer 
elect to declare Foo one way versus the other?  In order to communicate to 
the clients of Foo which of these contracts Foo allegedly does satisfy, 
where the difference lies in the unchecked and not necessarily formalized 
parts of these contracts.  Of course, if Foo's programmer is fallible or 
malicious, he may say "Foo implements Stack" when Foo does not.

Because Java uses (essentially) name-based type equality, Bar's programmer 
may declare a parameter to be a Stack.  This ensures that any argument bound 
to that parameter will 1) meet the enforced correctness criteria of Stack 
(which in this case is the same as Queue), and 2) was alleged by its 
programmer to actually be a Stack.

Both rely(Stack) and suspect(Stack) also fit the above description.  The 
difference is in the significance attached to #2.  rely(Stack) says that Bar 
may depend on this alleging by Foo's programmer.  suspect(Stack) says that 
Bar may not -- it may only depend on the enforced correctness provided by 
the "Stack" declaration.


>Now I am really confused.  Let me try to illustrate what I think MarkM is
>trying to get at with an example.  Take a hashtable object (like the
>java.util.Hashtable).  It has operations:
>
>def hashtable {
>  to put (:any key, :any value) :void { ... }
>  to get(:any key) :any { ... }
>  to delete(:any key) :any { ... }
>}
>
>The hashtable can be written so it does not rely on (is not at the mercy
>of) the value object.  That object reference is merely saved and returned,
>it is not invoked.  The hashtable does rely on (is at the mercy of) the key
>object.  The hash table is going to depend on the key providing a stable
>hashcode, and an equals operation which has certain characteristics (e.g.
>commutativity and stability over time).
>
>The :any auditor can not check these characteristics.  I also believe that,
>in general, no automatic system can check them. 

Yes, thank you!  This is indeed what I'm trying to say, and this is a great 
example for explaining it.  However, this isn't quite E for two reasons.  

1) Syntax.  Here it is with syntax corrected:

    def hashtable {
        to put (key :any, value :any) :void { ... }
        to get(key :any) :any { ... }
        to delete(key :any) :any { ... }
    }

2) Hashing and hash tables are hidden inside the E implementation / UTCB.  
Hash values are not exposed, and hash tables are therefore a primitive type 
in E -- the various kinds of Maps.  This hides the non-determinism that 
EQ-based-hash-values would expose, and it allows E's Maps to avoid relying on 
their clients -- the correctness of an E Map is not vulnerable to the 
objects stored in the map.

However, this example still clearly gets the point across.  I hope to post 
richer examples soon -- perhaps by annotating the examples in the Ode.


> This makes the
>rely/suspect pair very much like the /*null OK*/ comment convention adopted
>by Java programmers to document whether a parameter/return value could be
>null. 

Actually, the /*null OK*/ style started in the Xanadu days, probably from 
Dean, Ravi Pandya, Eric Hill, or myself.  It was translated from Smalltalk and 
C++ into Java and Original-E at Agorics and Electric Communities.

> MarkM is suggesting some automatic checking on the part of the
>compiler to warn about certain assignments.

Besides assignments, also variable initialization, including especially the 
binding of an argument to a parameter.  Perhaps some other cases as well, 
I'll know better when I work up a real example.  In any case, this is about 
right for the level of ambition I have in mind.


        Cheers,
        --MarkM