Extra Ideas

Ka-Ping Yee ping@lfw.org
Mon, 19 Oct 1998 02:31:33 -0700 (PDT)


Further to the message "Good Things About E":

Objects with a run method are like functions -- we can turn a
"function" into a "method" in Python like this:

    >>> class Dog:
    ...     def bark(self):
    ...         print "woof!"
    ... 
    >>> d = Dog()
    >>> d.bark()
    woof!
    >>> 
    >>> def newbark(self):
    ...     print "arf!"
    ... 
    >>> newbark
    <function newbark at 80ad768>      # a plain old function...
    >>> Dog.bark = newbark
    <unbound method Dog.newbark>       # magically becomes an unbound method
    >>> d.bark()
    arf!
    >>> 

In E we can do this by delegating the method call:

    ? define DogMaker() {
    >     define barkfunc() {
    >         println("woof!")
    >     }
    >     define Dog {                 # note 1
    >         to bark {
    >             barkfunc
    >         }
    >         to setBarkFunc(func) {
    >             barkfunc := func
    >         }
    >     }
    > }
    # value: <DogMaker>

    ? d := DogMaker()
    # value: <Dog>                     # note 2

    ? d bark
    woof!
    
    ? define newbark() {
    >     println("arf!")
    > }
    # value: <newbark>

    ? d setBarkFunc(newbark)
    # value: <newbark>

    ? d bark
    arf!

    ?

(note 1: I would like to have written "define self" here,
as i assume this would mean that the code inside the object
would refer to the object as "self" rather than "Dog".
However, i suspect this would cause us to get, at note 2,
"# value: <self>", which isn't very informative. ..?..)


What about going the other way -- getting a "function"
from a "method"?

In Python this is simply

    >>> d.bark
    <method Dog.bark of Dog instance at 80acf48>

It can be invoked like this (the bound method object knows
both the function code and the instance):

    >>> f = d.bark
    >>> f
    <method Dog.bark of Dog instance at 80acf48>
    >>> f()                            # operates on d
    woof!

Or, you can get the unbound method directly from the class:

    >>> Dog.bark
    <unbound method Dog.bark>

    >>> g = Dog.bark
    >>> g
    <unbound method Dog.bark>
    >>> g()
    TypeError: unbound method must be called with class instance 1st argument
    >>> g(d)
    woof!


To provide the interesting abilities of functional
programming languages, do we need a macro which expands

    method(object, <method>, arity)

into

    define _ {                         # note 3
        define obj := object           # note 4
        to run(arg1, arg2, ...) {      # note 5
            obj <method>(arg1, arg2, ...)
        }
    }

so as to bring any particular method "to the front" as
the one standing in for the lambda?

(note 4: in some other languages you could write the
equivalent of "define object := object" to bring in
the current value of "object" from an outer scope.
What does "define object := object" mean in E?)

(note 3: this brace means "create me an object";
note 5: this brace means "make a me a new scope":
this needs to be pointed out to the E beginner.
There isn't any other way than "define _" to say
"make me an object" without "define"-ing anything
to be initialized to it, is there?)


Then, do we provide reduce (fold), map, filter, etc.?

Allow me to attempt an exercise in E...

    define fold(func, start, list) {
        switch(list) {
            match [] { start }
            match [car] + cdr { func(car, fold(func, start, cdr)) }
        }
    }

Does that look right?


On a totally different tack: now that we have optional type
information, will we need something like attempted assignment
(?=) to take the place of dynamic casting?



!ping