[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 ;-)