[Omake] test/object/Test14

Jason Hickey jyh at cs.caltech.edu
Thu Aug 2 12:07:48 PDT 2007


On Aug 2, 2007, at 9:45 AM, Aleksey Nogin wrote:

> 1) "Naive user / principle of lease surprise" argument. The goal of  
> foreach is to be a simple iterator. For an array A, there should  
> not be a difference between "A.foreach(key)" and "foreach(key, $A)".
>
> 2) "Namespaces" argument. Prior to the method call, we have to  
> disjoint unrelated namespaces - the "this" namespace of the caller  
> and the object fields namespace. Our implementation not only  
> confuses the two, but allows the object namespace to "steal" from  
> the "original this" namespace.
>
> Note that in the above example, even if "map" was not an object  
> field, it will become one under your semantics. Also note that the  
> fact that the function arguments are currently in "this" namespace  
> only makes it easier to hit this problem, but it has no direct  
> relation to it.
>
> 3) "High-level straightforwardness" argument. Fully exported  
> fragments of code ought to be locally equivalent to imperative  
> interpretation.

I don't agree with any of these arguments.  We really must not define  
some funky semantics of binding.  Let me give a different example, to  
show that this has nothing to do with exports/hoisting.

X. =
    x = 0

    f() =
       println($x)

    Y. =
       x = 1

       call() =
           f()

    Y.call()

The program prints "1".  This is because, even though f() is defined  
as a method of X, it is called as a method of Y.

The real issue is the meaning of a simple application f().  What it  
currently means is that the function f should be called as a method  
of the current object--regardless of where f() was originally  
defined.  There are lots of other examples, like "f = $(A.B.C.g); f 
()" will extract the method A.B.C.g and call it as a method of the  
current object, etc.

We _could_ choose the alternative semantics, that methods are  
strictly bound to their object, and so a method value would have to  
be a kind of closure.  But it wouldn't work very well, because the  
closure would be statically defined.

Alternatively, we could rewrite the code to do what we think the  
programmer really meant, but I don't like it.

X. =
    ...
    Y. =
       ...
       call() =
          X.f()

Do you see why this example is related?  The problem is that in  
"A.foreach(key => ...)" the function "key => ..." is called as a  
method of A, not a method of the current object, so when you define  
this.map you are defining a field of A.  Again, it has nothing to do  
with hoisting.  There is the dual problem that A's fields shadow the  
function parameter.

All that being said, we could think about some way to get what you  
want specifically for foreach.  Basically, a way to do the following  
translation.

    Original:

       A.foreach(key => exp)

    Translates to:

       apply(key) =
          exp
       public.obj = $(this)
       A.foreach(key => ...)
           obj.apply($(key))
           export
       this = $(obj)

In any case, I think we should undo the changes to the hoisting code.

Jason

--
Jason Hickey                  http://www.cs.caltech.edu/~jyh
Caltech Computer Science      Tel: 626-395-6568 FAX: 626-792-4257





More information about the OMake-Devel mailing list