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

Evan Simpson evan@tokenexchange.com
Sat, 5 Dec 1998 12:33:35 -0600


<Applaud!><Whistle!><Cheer!><WooHoo!>

You've had a genuine Aha! moment, and what's more you've shared it
successfully.  I thank you.

Despite your excellent exposition, I still feel the need to sum up, if only
to confirm my understanding.

*** summary, with one question ***

1. Objects is objects.  Period.  They can store stuff in their namespace.

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

3. If you give an object a name, you've made a class.  This allows you to
search the inheritance DAG by name.

4. Simple attribute operations on a baseless object act on its namespace.

5. A based object checks to see if its base objects want to control
attribute operations.  If not, it falls back on #4, then asks the base
objects for attributes not found in its namespace.

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')?

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.

8. The type/class of an object is its base tuple, or None for baseless
objects.

*** consequences and opportunities ***

9. "class A(B, C):" constructs an object with bases (B, C), names it "A",
and binds it to the local namespace as "A".

10. "a=A()" constructs an object with base (A,) and no name, and binds it to
the local namespace as "a".

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()"?  How does this mix with __call__?

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.

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!

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

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

*** 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.

Suppose objects could have a __birth_hook__ method, called every time a new
descendent is created.  Unlike __init__, this would be called on named and
unnamed objects alike, and before __init__ for unnamed objects.  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 ;-)