Some thoughts on the 'reveal' operator

Chip Morningstar chip@communities.com
Thu, 23 Sep 1999 16:59:31 -0700 (PDT)


<Note: These are some remarks I made to MarkM in a correspondence I had with
him earlier today as I was giving him some feedback on his draft FC'00 paper.
He suggested that as thse concerns the language design in general rather than
the paper in particular, I ought to share them more broadly, so here (in
slightly edited form) they are.>


The reveal operator ("^") is a new addition to E for me. I thought it was a
typo when I first saw it. I think I understand what the motivation for this was
but I also think it's really icky from a human-factors perspective to have to,
in essence, put an explicit "return" statement in *every* block. (It's also
problematic to my eyes to have such a significant operation expressed by such a
small and hard to see character glyph, though I imagine people with a lot of
Smalltalk experience will be more used to it.) In particular, in the example:

   define factorial(n) {
      ^if (n <= 0) {
         ^1
      } else {
         ^n * factorial(n-1)
      }
   }

The reveal on the two inner result expressions seems clear enough, but I found
the reveal on the 'if' to be quite surprising and counterintuitive, since I'm
not (yet) used to thinking of statements with a statement-like syntax as
expressions. This is particularly the case in this example since you need both
the inner and outer reveals to actually return a result; omitting one but not
the other in this example yields useless crud:

   define factorial(n) {
      if (n <= 0) {
         ^1
      } else {
         ^n * factorial(n-1)
      }
   }

*Looks* right, but will be (in C terms) a function returning void. Whereas:

   define factorial(n) {
      ^if (n <= 0) {
         1
      } else {
         n * factorial(n-1)
      }
   }

is just wrong. I would expect it to (a) throw an exception (effectively
crashing the program in this example), (b) silently do something wrong (very
bad), or (c) get caught by the compiler (which will feel to the programmer like
one of those pedantic complilation errors where the compiler is objecting to
some purely formal deviance rather than to something substantive, the kind of
error where you tend to think "hey, if the compiler knew *that*, why didn't it
just do the right thing?" -- never mind that the right thing isn't actually
100% obvious, that's what programmers will think).

I understand that this is trying to make revelation explicit, presumably so
that it becomes a deliberate act (for example, so that a function does not
inadvertantly reveal information that was not meant to be revealed, simply
because that information happened to be the last thing computed). That's a
laudable goal, but I suspect the mechanism will prove cumbersome. Falling back
on the custom of using the value of the last expression in a block as the value
of the block seems to me a more pragmatic design. If we need to have an
explicit value that denotes a non-result for the "I'm not really returning
anything" case, that's OK with me.