[Types-sig] Why have two hierarchies? (*EUREKA!*)

Just van Rossum just@letterror.com
Sat, 5 Dec 1998 20:47:18 +0100


Evan Simpson wrote:
><Applaud!><Whistle!><Cheer!><WooHoo!>

<bow>

(-- sounds of grumbling demi-gods in the back of the room --)

Cool summary, mostly correct. A couple of comments and a question in return.

>2. Objects are based on other objects.  This forms an inheritance/delegation
>DAG exactly like current class DAGs.

What is a DAG?

>3. If you give an object a name, you've made a class.

That *could* be a possibility. So far, it makes a lot of sense to me, but
this detail is not very important: as long as there is _some_ way to
distinguish a class form an instance.

>This allows you to search the inheritance DAG by name.

Sorry, I don't follow. What is a DAG?

>6. When a function 'f' is an attribute of a named object, the object's kids
>see 'f' as a method.  Named kids see 'f' unbound, unnamed kids see it bound
>to themselves.  QUESTION: How do bound methods behave? Do they require an
>unnamed object (an 'instance')?

Not as far as I'm concerned: a bound method will probably automatically
have an im_self attribute of the right class, but if you're calling an
unbound method I strongly feel it's the responsibility of the caller to
pass an object (*whatever* object) that the unbound method can handle.

>7. (Not sure on this one) An object can bind a method to itself before
>handing it to its kids, thus allowing the elusive static class method to be
>realized.

Not sure about this one myself. The easy way is to keep doing what we've
always done:
    MyClass.foo(MyClass, ...)

>What about:
>11. "class A2(a):" constructs an object as in #9, but its base is the
>unnamed object from #10.
>Do we allow this, or require bases to be named? If we allow it, do we allow
>"b = a()"?

That maybe a fuzzy part of my scheme indeed. I haven't fully thought this
part through yet.

>How does this mix with __call__?

My demo implementation is broken in this respect. After I posted the stuff
I thought of the obvious solution. Hm, solution is the wrong word: I just
implemented existing Python's call semantics wrongly. It _should_ work like
this:

    - if the object we're calling is an instance, search for a
      __call__ method
    - if the object we're calling is a class, do one of these (don't know
      what's better, possibly the latter):
        a) construct a new class with (name, (self,), {}) as arguments,
           search for an __init__ method, call it if found. (just like
Python Classic)
      or
        b) search for a __instantiate__ method, let it handle (a)


>12. "a = class (A):" or "a = object (A):" could be a synonym for #2, but
>allow a code suite to execute in the context of 'a's namespace.

I don't quite follow...

>13. "a = class:" or "a = object:" could perform the same function for
>baseless objects.
>We would now have a simple way to spell nested structures:
>
>a = object:
>  a1 = 1
>  def null(): pass
>  a2 = object:
>    b = "hi!"
>#a.a2.b == "hi!"
>#a.null is a function, not a method!

Hmmm, not bad... But it is the same as:

class a:
    a1 = 1
    a1 = 1
    def null(): pass
    a2 = object:
       b = "hi!"

a.__name__ = None

;-)

>14. "5.__base__ is type(5) is Integer", "5" is nameless, and "
>type(5).__name__=='Integer' ".

I don't know what you mean by type... But yes, something in __bases__ makes
it an integer.

>15. The holy grail "class myInt(Integer):" is attainable.

Phew.

>*** last minute thought ***
>
>I am bothered by the need to search the inheritance DAG for attribute
>operators every time you use one.  Caching and other possible optimizations
>don't make me feel any better - I can't say exactly why.

I have similar feelings. Right now, my helper method __getattr_from_bases__
uses __getattr__ on each of the bases. Maybe it should just recursively
search their __namespaces__. If you want to override that behaviour: just
define a custom __getattr__ which does what you want.

>Suppose objects could have a __birth_hook__ method, called every time a new
>descendent is created.

Right, this is exactly what I meant with __instantiate__ above.

>Unlike __init__, this would be called on named and
>unnamed objects alike, and before __init__ for unnamed objects.

Erm, confusion: are you creating an unnamed object from a named base or a
named or unnamed object from an unnamed object???

>Objects
>which redefine __init__ have to cooperate with ancestral __init__s by
>calling them explicitly, but __birth_hook__ is forced on them.  It would be,
>among other things, a chance to install __*attr__ hooks into the namespace
>of the new object.  "Static class methods" could be installed in subclasses
>(kids with names).  We could keep the current namespace-then-delegate model,
>but still allow hookers ;-)

At the conference hotel in Houston, there was a bar called "Hookers Nook"...

Just