[Python-3000] Anti-use-case for type annotations

tomer filiba tomerfiliba at gmail.com
Sat May 20 10:31:04 CEST 2006


i've been crying about that for quite a long time, but it seems people
failed to see
my point: type checking, which is more easily enforced by type annotations,
is bad.

and because it will have this nice (and pointless*) syntax, lots of
people will start
using them everywhere, and make projects like mine (RPyC) or PYRO worthless.

this kind of projects relies on proxies -- objects that *look* like
the object they
point to. like weakref.proxy. of course these objects don't have the *type* of
the pointed object, they only have it's attributes, or rather, they deliver all
__getattr__s and __setattr__s to the remote object, and re-raise exceptions
locally.

when type annotations become so handy, everybody will start using them,
and it will greatly limit the use case of proxies. my proxies give you something
that looks like a file, i.e, you can .read from it, .write to it,
.close it, etc., but
isinstance(f, file) is False.

in fact, version 2.55 of RPyC provided a replacement for isinstance that can
test for proxies (recursively goes up the __bases__, and serialzies each type
as a filename.typename string, which is unique enough), and you can do
__builtin__.isinstance = Rpyc.isinstance, and then throughout your code
you can work with NetProxies. but it's uber *nasty*, and doesn't work with
builtin modules/classes/functions (they bind directly to the "real" isinstance)

so that's an anti-use-case for type annotations. when people start
using those, they would effectively stop using duck-typing, since the
type of the object must be well-defined, and thus render "look-alike"
objects useless.

------

* pointless -- type annotations basically subclass an existing
container type (list,
tuple, dict) and simply add type checking to append/insert/__setitem__, so
that wrongly-typed objects can't accidentally get into the container.

but it's python, not java, so you could always call the super's __setitem__
and break the whole idea.

i would expect that specialized type of be optimized for that given type, i.e.,
reserve only the required space for that type, etc. but i understand that's not
the case. so why not just do something like this instead:

>>> def ListOf(oftype):
...     class meta(type): # just for pretty repr
...         def __repr__(self):
...             return "<type %s(%s)>" % (self.__name__, oftype.__name__)
...     class ListOf(list):
...         __metaclass__ = meta
...         def __init__(self, seq = []):
...             self.extend(seq)
...         def append(self, value):
...             if not isinstance(value, oftype):
...                 raise TypeError("invalid type")
...             list.append(self, value)
...         def insert(self, index, value):
...             if not isinstance(value, oftype):
...                 raise TypeError("invalid type")
...             list.insert(self, index, value)
...         def extend(self, iterable):
...             for item in iterable:
...                 self.append(item)
...         def __setitem__(self, index, value):
...             if not isinstance(value, oftype):
...                 raise TypeError("invalid type")
...             list.__setitem__(self, index, value)
...     return ListOf
...
>>>
>>> intlist = ListOf(int)
>>> intlist
<type ListOf(int)>
>>> l = intlist([1,2,3])
>>> l.append(4)
>>> l.append("a string")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 11, in append
TypeError: invalid type
>>> print l
[1, 2, 3, 4]
>>> isinstance(l, intlist)
True
>>>

that way, with dicts, you can have keyword arguments

d = DictOf(key = str, value = int)
or
d = DictOf(key = str, value = (int, str))
(int, str) means int or string, because isinstance can accept a tuple of types.

so who needs type annotations? the only thing they are good for is
better/automatically documenting code. but is better documenting
worth imposing restrictions on the langauge, as in the proxying case?
is better documenting worth breaking duck typing?

something that looks like a file but does not inherit from file, cannot be
used by a function that expects a file, although all it needs is a "read"
attribute!

-------

but if you think type annotations are the way to go, i'd ask that the type-
checking functions, like type or isinstance, would call a special __type__
method of the object.
i.e., type(x) ==> x.__type__()
which would normally return x.__class__, but in the case of proxies, it
would return the type of the proxied object.

by the way, how about renaming type(x) as typeof(x)? it's quite ugly
that "type" is both a factory for types as well as a function that returns
their type, and it depends of the number of arguments.
type(name, bases, namespace) --> create a new type
typeof(x) --> return the type of x




-tomer


More information about the Python-3000 mailing list