[e-lang] Bug (0.8.26g): InStream.obtain has wrong argument types

Kevin Reid kpreid at attglobal.net
Thu Apr 15 10:53:44 EDT 2004

On Apr 15, 2004, at 0:03, Mark S. Miller wrote:

> At 02:52 PM 4/14/2004  Wednesday, Kevin Reid wrote:
>> jsrc/org/erights/e/elib/eio/InStream.java:
>     Object obtain(int atLeast,
>                   int atMost,
>                   String sched,
>                   String proceed,
>                   String report)
>       throws UnavailableException, IOException;
>> If my understanding is correct, 'proceed' and 'report' should be 
>> boolean.
> What I have in mind is to use Strings as essentially enum values, as 
> is the
> common practice in Scheme, Lisp, or Smalltalk. Using for the moment a
> hypothetical enum declaration syntax, what I have in mind would be 
> something
> like:
>     Object obtain(int atLeast,
>                   int atMost,
>                   enum{NOW, WAIT, LATER} sched,
>                   enum{ADVANCE, QUERY} proceed,
>                   enum {ELEMENTS, STATUS} report)
>       throws UnavailableException, IOException;
> I figure it makes calls more understandable if they looked like:
>     ... obtain(0, 1024, "NOW", "ADVANCE", "ELEMENTS")
> rather than
>     ... obtain(0, 1024, "NOW", true, true)


> This was all designed before I heard of the "type safe enum" pattern
> http://java.sun.com/developer/Books/shiftintojava/page1.html , now a 
> part of
> the Java 1.5 language http://www.jcp.org/en/jsr/detail?id=161 . This 
> pattern
> is, in some real sense, more properly object-oriented than any other 
> way
> I've previously encountered of doing enums. For reasons I'm not sure I 
> can
> explain, I have mixed feelings about this pattern, and have done 
> nothing
> with it or about it in E. Opinions?

As Dean Tribble said 

   Hence, a distributed programming language is either untyped or
   confused.  Which would you rather have?

The notion of a 'type-safe enum' implies well-defined types. This may 
explain your mixed feelings.

Hypothesis: Using strings as enum values is exactly as good/bad as 
using strings as method names. It has exactly the same potential for 
confusion if the wrong enum (or wrong object) is passed to some code.

Here are some ways to implement enumerations. If I were 
defining/implementing EIO now, I would choose #4.

I would also make all of the EIO constants available as a ConstMap so 
that they can be imported easily:

   def [=> NOW, => WAIT, => LATER,
        => ADVANCE, => QUERY,
        => ELEMENTS, => STATUS    ] := <elib:eio.enum>


   def QUERY := "QUERY"

Not 'safe': these values can be confused with any other enumeration.


   def ADVANCE {}
   def QUERY {}

This is a straightforward implementation - the enumeration values are 
!= all others. Unfortunately, they are also distinct from the 
equivalent objects loaded from a different <import> (assuming emaker 
semantics), and so won't work between vats, which I assume is desired 
for EIO.


   def ADVANCE implements PassByCopy {}
   def QUERY implements PassByCopy {}

Assuming that a PassByCopy object's state (for sameness purposes) 
includes its source code and FQN, and that all EIO implementations use 
the same FQN-prefix, this would work.

Of course, we don't have E-language PassByCopy yet. (We don't have EIO 
yet either.)


   def ADVANCE := "org.erights.e.elib.eio.InStream.ADVANCE"
   def QUERY := "org.erights.e.elib.eio.InStream.QUERY"

This is equivalent to the previous, except that its values happen to be 
Strings, and therefore are PassByCopy in current E.

Also, the length of the strings may discourage programmers from using 
them literally in their programs, for whatever that's worth.


   def ADVANCE implements PassByCopy {
     to __printOn(w) :void { w.print("ADVANCE") }
     to run(visitor) :any  { visitor.advance() }
   def QUERY implements PassByCopy {
     to __printOn(w) :void { w.print("QUERY") }
     to run(visitor) :any  { visitor.query() }

Specialized PassByCopy enums could have arbitrary behavior. However, 
this would make them unequal to older versions of themselves if the 
slightest change is made.


A Java type-safe enum could be made PassByCopy via ELib. I dislike this 
reliance on semantics which can only be defined in the TCB (the Java 
type namespace being considered global).

def Enum {
   match [`get`, values] {
     def valuesSet := values.asSet()
     def Enum1 extends __templateGuard(Enum1) {
       to getName() :any { `Enum$values` }
       to coerce(specimen, optEjector) :any {
         if (valuesSet.contains(specimen)) {
           return specimen
         } else {
           throw.eject(optEjector, `Must be one of $values`)

def constants := accum [].asMap() for x in ["NOW", "WAIT", "LATER", 
"ADVANCE", "QUERY", "ELEMENTS", "STATUS"] { _.with(x, 
meta.context().getFQNPrefix() + x) }

def [=> NOW, => WAIT, => LATER, => ADVANCE, => QUERY, => ELEMENTS, => 
STATUS] := constants

interface InStream {
   to obtain(
     atLeast :int,
     atMost  :int,
     sched   :Enum[NOW, WAIT, LATER],
     proceed :Enum[ADVANCE, QUERY],
     report  :Enum[ELEMENTS, STATUS],

Kevin Reid

More information about the e-lang mailing list