From Edward Welbourne Thu May 6 20:49:24 1999 From: Edward Welbourne (Edward Welbourne) Date: Thu, 6 May 1999 20:49:24 +0100 (BST) Subject: [Types-sig] Re: suggestion: replace class with a generic generator statement Message-ID: Tim ended with the pertinent remark that if class weren't going to do what it currently does, then my suggestion would be dead already. One of my primary aims was, indeed, to ensure that classes and their instances (the things produced by calling them) behave like we're used to. I'm fairly sure I succeeded - though class becomes a builtin rather than a reserved word and it's all *implemented* differently - so I must infer that I've explained it poorly ... This is no surprise. Please *do not feel embarrassed* if you haven't understood me - explaining my thoughts isn't my strong point ... but answering specific questions I can usually manage: indicate which piece of text did the confusing, ask a question on which you're stuck, explain what you *do* understand (even if you're not sure) and I might spot what I've failed to explain. Eventually, I might even improve the pages to the point where they make more sense ... Furthermore, some clumsiness with my source-control tools at home meant the web-site was missing various fragments until this evening (crucially, class.py - see below). Please, if you trip over any broken links, tell me about them, even if you don't understand their context ! Victor (who has > an intuition about the overall idea so maybe there's hope for my writing after all ;^) said: > ... meta^N-objects are supposed to do for meta^(N-1)-objects ... There's an important point here - meta vanishes: meta^N = meta^(N-1) for all N. Indeed, the meta-class McLass defined in http://www.chaos.org.uk/~eddy/dev/toy/class.py is a class and can't really tell that it wasn't created by instanciating itself - except, of course, via the standard ontological proof ... It's possible (given that I'm fairly sure of that code being `right') that reading class.py will be more intelligible than reading my English. Note that my calling the module class.py is deliberate `pushing the boat out a little': the module provides a __call__ function and I really want *any* object, ob, to be callable if ob.__call__ is callable. However, the class.__call__ function defined in class.py could equally have been defined as __builtins__.class as far as anything important cares. It needs access to McLass, but that's all. Indeed, McLass is the important thing in all of this ... Now, Victor also said: > Edward, could you elaborate on your vision about the relationships > between objects/classes/metaclass(es)/types and which of these > entities exist according to you? Right, so the first thing is that meta-classes vanish. The existing class notion will continue in being with (almost) its existing semantics. We can still use the name `instance' for the kinds of thing produced by calling a class (i.e. by calling its .__call__() attribute). However, I don't see class instance module package being different types (in the existing sense): the underlying C or Java will be treating *all* of these in the same terms. I dream about getting the other types (except probably actual functions, as generated by the def statement) to be of this one type, but that's a dream until I write the C toy (on which, for various reasons of distraction, I've done nothing for months - sorry) and not necessary to the present scheme. Each of these flavours of name-space/object will have an assortment of callables in its __lookups__ attribute: the difference between classes and modules will just be a difference in what callables the object uses to do its attribute lookup. The differences between classes and instances will be down to the data in the concealed arguments of these callables (so it'll be rather hard to detect). Continuing to take Victor's message in reverse order, > I'm unclear on what the class/object model looks like. Well, yes, I didn't explain it very well. I'll try a sketch ... Refer to anything with a name-space as an `object', whether it's a class, instance, module, package, ... or whatever. An object's name-space is *entirely* consequent on and controlled by its magic attribute, __lookups__, which is a list of callables. The *only* thing getattr does is (schematically): def getattr(obj, key): for lkp in obj.__lookups__: try: return lkp(key) except AttributeError: pass raise AttributeError, key except that (see python.py) the __lookups__ attribute itself is accessible before getattr gets involved - the actual implementation of getattr() is *simpler* even than this schematic. Python has various magic names, __magic__, associated with supporting the various interfaces defined in the language (e.g. magic in [ add, mul, call, setattr, delattr, getitem, setslice ]). These are carried over verbatim into the new regime. (But __dict__ ceases being magical, being demoted to merely an implementation detail of some of the other magic - setattr, delattr and one of the callables in the object's __lookups__ list - retained for backwards compatibility). The entire semantics of *all* the flavours of object are defined in terms of these magic attributes and the __lookups__. So, e.g., if an entry in obj.__lookups__ returns an answer to input '__setattr__', this had better be a callable, taking (key, val): when a piece of code attempts to execute obj.name = value, this callable will be invoked (and if no such callable is available, the code obj.name = value will raise AttributeError('__setattr__')). Invoking it needn't change the result of calling getattr(obj, 'name'): albeit, in such a case, we might be somewhat irritated by whoever implemented the object in question. Note that each lookup was just given a key (not, e.g., lkp(obj, key)) and the obj.__setattr__ function was called with args (key, value). This has to be managed by using curried functions, but one can do those in python (though I suspect my suggestion will make a builtin currie() function necessary in practice): the value of obj.__setattr__ is probable the same as lambda k, v, __o=obj: __o.__class__.__setattr__(__o, k, v) but all of that is hidden inside the machinery of the builtin callable class(). OK, that's a start: ask more questions, get more answers ... Eventually I'll try to fill the quite proper request someone made to put an outline into just one screen-full. Eddy.