[e-lang] E gotchas

Ka-Ping Yee e-lang@mail.eros-os.org
Mon, 3 Jun 2002 10:35:15 -0700 (PDT)

Here are some issues i encountered while developing auditors.

1. Punctuation.

In some cases i am put off by how much punctuation i have to write.
What in Python would have been

    if guard.name not in frozenGuardNames:

must in E be written

    if (!(frozenGuardNames contains(guard name()))) { ... }

Two punctuation characters become eleven, and the readability of
the code suffers a lot.  Ouch.

Four extra levels of parentheses are required in E.  They come from:

    1.  The need to call a nullary method explicitly to retrieve
        the guard's name.

    2.  The lack of an 'in' operator, requiring one to call a
        'contains' method explicitly.

    3.  The lack of a 'not in' operator and the precedence of '!'.

    4.  The requirement of an extra pair of parentheses as part
        of the syntax of 'if'.

2. Method naming.

Methods named 'name()' and 'getName()' are scattered among the
various classes.  It is impossible to guess which name to use.
In writing the deep-frozen auditor i had to use both.

Some sort of semantic convention needs to be established about
when to say 'get' and when not to say 'get'.  I remember suggesting
that 'get' means you are retrieving a component of the object's
state, but Mark saying that 'get' was more general than that.
But too general a rule would have us put 'get' in front of *all*
methods that return anything.  I'd like the rule to have one right
answer, yes or no, as often as possible.

Here are some possible conventions, though i am not sure if they
are good ones:

    - Use 'get' when returning a component of the object's state.

    - Use 'get' for any method that's idempotent.

    - Use 'get' for any method whose job is to ask the object
      "What is your ...?", as opposed to a method that commands
      the object to do something.

I'd like to hear other ideas from everyone.  What does 'get' mean
to you?  What's your own convention for using 'get'?

3. toString() and printOn()

I was burned by this when using the E interactive interpreter
to explore the structure of an EPattern.  I did

    ? def p := epatt`i`
    # value: epatt`i :any`
    ? p getAllegedType()
    # value: FinalPattern

and then wrote

    if (p getAllegedType() != "FinalPattern") ...

This didn't work, and it took a long time for me to figure out why.
What got me was that the appearance of a TypeDesc in the interpreter
looked like a plain string.

I later discovered that strings print out quoted (as they should),
but perhaps it would be good to adopt a convention for representations
of objects that cannot be typed back in.  Python's convention is to
use angle brackets, which works pretty well; with this convention
the above might look like this:

    ? p getAllegedType()
    # value: <TypeDesc "FinalPattern">

4. return, continue, break

What do you expect the following to do?

    for i in 1..5 {

Strangely, it prints all the numbers from 1 to 5, not just 1.
"continue" and "break" look right but silently don't work!
This was a major surprise -- of exactly the kind you are trying
to avoid: a silent, startling change in behaviour for a familiar
C-like construct.  It took some scratching my head before i found
the correct answer:

    for i in 1..5 {

Subtle indeed, and most severe.

'return' doesn't work at all; i had to define it using escape.

I wish we could make all three of these keywords, and just have
them work properly.

-- ?!ng

"To be human is to continually change.  Your desire to remain as you are
is what ultimately limits you."
    -- The Puppet Master, Ghost in the Shell