I digress, badly. Since I want the main thrust of the discussion to read well, I know I have to remove the digressions. Being somewhat shy of actually deleting them, I move them aside. Here they loiter …
Note that one could arrange for the built-in types to have
all their magic attributes by having the interpreter fake these up, when called
for, using on-the-fly lambda expressions: they need not be carried
around by the built-in objects themselves … though I believe this can be
made the cheaper solution.
Rumour has it that Guido intends to change the behaviour of integer division
so that it coerces to float (if needed ?), which sounds eminently sensible: and
we'll still have divmod for the rounded
form.
*s Keyword arguments are allowed to use the names of safe tunnels,
provided the ** has an identifier: they appear, with their values,
in the dictionary bound to this identifier. Safe tunnels need to be invisible,
hence so do their names. This matches the present handling of the names of
*-item and **-item:
>>> def demo(*args, **what): print what
...
>>> demo(what=1, args=0)
{'args': 0, 'what': 1}
There is nothing to stop us allowing the ** to appear
among, or even before, the purely positional parameters: this would forbid
supplying the later purely positional parameters as keyword arguments, obliging
callers to provide these inputs as positional arguments; indeed, placing
** before even one of the positional parameters would
force all of these to be supplied by positional arguments. Equally, I have
thought of no strong argument in favour of this liberty.
In a similar vein, it'd be entirely reasonable to allow parameters, after
the single *, to be given without values, implicitly reading each
such name as name=name, transcribing this name from
the suite which defines the function into its execution initialisers.
Under the bonnet, a namespace object, obj, is a packaging of a
python-callable, func, and getattr(obj, key), finding
its first argument to be of the namespace-object type, calls the
func packaged by obj, delivering
func(key); so obj.name is
func('name').
When running the suite of a builder statement in the name-space of a
suite-wrapper, the interpreter will be catching AttributeError, if
raised by attribute lookup or deletion on the suite-wrapper, and transforming it
into NameError.
>>> class dummy: del nom ... Traceback (innermost last): File "<stdin>", line 1, in ? File "<stdin>", line 1, in dummy NameError: nom >>> class dummy: nom ... Traceback (innermost last): File "<stdin>", line 1, in ? File "<stdin>", line 1, in dummy NameError: nom
I've also seen a proposal which provided for temporary namespaces,
along the following lines (here using keywords using and
do: I forget what the original used):
using:
x = 7
y = 32
do:
z = x * y
in which x and y are temporary variables,
visible only during the suites of using and do,
z gets set in the enclosing namespace, but the temporary variables
are read-accessible during the do clause which sets it. I can
model this by using an anonymous namespace object borrowing from our original
locals, providing no attribute modifiers of its own (so it'll borrow these from
locals) but with a suite-wrapper which does carry attribute modifiers, which
alter what the anonymous object's namespace dictionary (which the suite-wrapper
alone can see as __dict__) contains. Use this suite-wrapper for
the using clause's suite, use the anonymous object itself for the
do clause; the former will store attributes on the anonymous
object, the latter will read from it but store in the original locals. Discard
the anonymous object and its suite wrapper when you are done.
I haven't given much thought to the built-in type: I'm
confident that all uses of it should be replaced with uses of
isinstance, and I ultimately only believe in one type
– function – albeit (necessarily) in two packagings: one as a python
function, the other as a python lookup (i.e. namespace). All other types are
illusions created by artful arrangments of objects and behaviour (and interfaces
are what matters).
It will be necessary for objects (lookups) to support some form of do you
support this interface
questions, but these can (and should) be packaged
using a magic method name: e.g. obj.__supports__ which takes some
description of a python interface and returns true or false. This, however,
doesn't interfere with what I'm doing, so I'll leave it to the hard-working
souls who have devoted lots of time to thinking about describing
interfaces.
While the basic infrastructure of python.py provides
for objects whose namespaces are fixed once built, it may also (see the
types-sig archive at python.org) be worth providing for modification of a
namespace to be type-checked
– that is, some infrastructure which;
stores checker functions keyed on attribute name; when attribute modification is
attempted, if the modified name has an associated checker, the value to be
stored gets passed to the checker function, requiring (say) a false result for
the modification to go ahead, reading true result as what the problem
was
. See also: check.py
Note that it is possible for such a checker to embrace deletion,
signalled by calling the checker with no value to check. In general, one can
use the withargs() hack to detect
called with no argument
, but more simply one can have the checker use a
known default that it'll either reject or accept according as one wishes to
allow or forbid deletion; thus
obj.__getchecker__('mystringattribute') could return
def mustbestring(val=''):
return type(val) is types.StringType
# default of '' allows deletion of obj.mystringattribute in this case;
# default of None would forbid it.
.__method__ problem My suggestions deliberately err on the side of trying to stay as like python
1 as practical; but having a sub-namespace of a class to carry the
method-functions to be inherited by instances is unavoidable. This leads to the one place where my suggestions will require
a change to working code (as opposed to expanding the range of things that will
work): where the methods of a class are looked up directly in the namespace of
the class, as when a derived class over-rides a base's implementation of some
method with a replacement which calls the method it's over-riding
(e.g. __init__ and __del__). In such cases, the
lookup will have to dereference via the name (here taken to be
.__method__) of the sub-namespace which carries the class' methods;
mybase.__init__(self) will become
mybase.__method__.__init__(self).
Given that python 2 may involve changes dwarfing this, one alternative solution is to be forthright about this change: chose nice friendly names for the sub-spaces (drop the __ prefix and suffix, at least), dump the sophisticated initialisation wrapper of the new class and have normal class statements actually reflect the real structure of what gets built:
class new (old):
instance method (method):
def func(self, first, *args, **what, oldmeth=old.method.func):
self.primal = first
return apply(oldmeth, (self,) + args, what)
The instances of new will then inherit from new.meth, so
invoke this method as self.func(…) as at present. This will
force greater code-change, but might be a better approach: if nothing else,
it'll let us put functions into the namespace of the class (on its data side)
which aren't meant to be used as methods but simply as functions.
However, reverting to my conservative line, there remain some ways to take the edge off the problem. In the one-base case we can try something like
class new (old):
def method(self, first, *args, **what, oldmethod=method):
self.primal = first
return apply(oldmethod, (self,) + args, what)
Note that we can read method, even though old.method
wouldn't work (nor would new.method) when evaluating defaults for
the new method's parameters – the namespace-object provided
by the class builder does ensure that new's
suite can read values in old.__method__'s namespace (because
the suite's local namespace borrows from new.__method__ which
borrows from the __method__ of each of new's bases).
Likewise we could pass the old value of method through the namespace of the new
class; but these tricks only work for the given method of one base. An
__init__ method may well invoke those of its class's bases one by
one; for this it is going to have to dereference through
__method__.
__bases__ to divert the .__method__ problem The __bases__ attribute could, at one extreme, be provided by
the interpreter as a keyword argument to builders (though I'm not fond of the
idea). In python.py I presume otherwise
– if only so as to show how a builder can provide such names. This
attribute could be set up by within, wrapped or
instance: but I have left it to builder to do so
(consequently, so does class), so that __bases__ is
only an attribute of classes (and builder classes).
The __call__ used by gennie could record the bases
of the .__method__ it sets up as the __bases__ to be
seen by the suite. This would enable the suite (and, in particular, hidden
tunnels into methods defined within the suite) to access methods supplied by
base-classes by reading them directly as attributes of the corresponding entry
in __bases__, rather than as attributes of the base-class'
.__method__. For example:
class new (recent, old):
def __init__(self, first, *args, **what,
oldinit=__bases__[1].__init__,
recinit=__bases__[0].__init__):
recinit(self, first)
return apply(oldinit, (self,) + args, what)
using __bases__[1] in place of old.__method__. There
isn't enough mileage in this to persuade me to change things around for its
sake, though.
Some tools would be much easier to build if only one had the tool
in question to hand with which to build itself. This is called the
boot-strap problem, in honour of the notion of pulling
myself up by my boot-straps
, a standard analogue of the classic which
came first: the chicken or the egg ?
paradox. One ends up building a
useful tool some harder way than with itself.
One of my aims in these games is to have the fundamental meta-class construction tool behave exactly as if it had been created by itself. Although we actually have to build it some other way, I want there to be no way of knowing that it didn't build itself other than to apply the causal argument that it wasn't available for use until it had been created, so can't have been used to create itself.
At some stage, I must check how well my suggested implementation of
builder measures up as a causal bootstrap.

Written by Eddy.