[Python-3000] Draft pre-PEP: function annotations

Calvin Spealman ironfroggy at gmail.com
Tue Aug 15 03:10:13 CEST 2006

On 8/14/06, Collin Winter <collinw at gmail.com> wrote:
> On 8/13/06, Paul Prescod <paul at prescod.net> wrote:
> > "In order for processors of function annotations to work interoperably, they
> > must use a common interpretation of objects used as annotations on a
> > particular function. For example, one might interpret string annotations as
> > docstrings. Another might interpet them as path segments for a web
> > framework. For this reason, function annotation processors SHOULD avoid
> > assigning processor-specific meanings to types defined outside of the
> > processor's framework. For example, a Django processor could process
> > annotations of a type defined in a Zope package, but Zope's creators should
> > be considered the authorities on the type's meaning for the same reasons
> > that they would be considered authorities on the semantics of classes or
> > methods in their packages."
> The way I read this, it forces (more or less) each
> annotation-consuming library to invent new ways to spell Python's
> built-in types.
> I read all this as saying that annotation processors should avoid
> using Python's lists, tuples and dicts in annotations (since whatever
> semantics the Python developers come up with will inevitably be
> incompatible with what some library writer needs/wants). Each
> processor library will then define my_processor.List,
> my_processor.Tuple, my_processor.Dict, etc as alternate spellings for
> [x, y, z], (x, y, z), {x: y} and so on.

I'm sorry but I don't see the logic here. Why will all the annotation
libraries need to invent stand-ins for the built-in types? They just
shouldn't define any meaning to standard types as annotations, leaving
the interpretation of int in 'def foo(a: int)' up to the python
developers. The only thing I can figure is that you see this need in
order for other annotation libraries to handle associating types with
arguments, but there is evidence that this shouldn't be done directly
with built-in type objects (unless defined by python itself). Using
the types directly doesn't cover important use-cases like adapting,
even tho we can expect it is safe with builtin types, we can not be
sure of this with all types, so there is a good chance the type
annotations will take the form of

   def foo(a: argtype(int))
   def bar(b: argtype(Baz, adapter=Baz.adaptFrom))

which defines that foo takes an int object and bar takes a Baz
instance, which can be adapted to with the classmethod Baz.adaptFrom.
Maybe Baz' constructor takes a database connection and object ID, and
would break just being passed a random object. In this case, we don't
need to use my_anno.Integer or something like that, because we aren't
(and shouldn't) use the built-in type objects directly as our
annotation objects.

I'll propose this as a new rule the PEP should define that annotation
handling libraries should not only avoid expecting instances of
built-in types as annotations (lists and strings, etc.) but also those
types themselves (using the int object itself as an annotation). It
may seem terribly convenient to use types directly, but its becoming
more and more apparent that all annotations should be wrapped in
something by which the meaning of the annotation can be reliably and
safely determined by its type, and no built-in type really does that
in an agreeable way.

Also, Collin Winter said:
> One particularly divisive issue is whether tuples should be treated as
> fixed- or arbitrary-length containers. Concretely, does
> "tuple(Number)" match only 1-tuples with a single Number element, or
> does it match all tuples that have only Number elements?

I would personally be completely adverse to the use of any containers
as a meaning of "This argument is a list/tuple of some specific
types". On on hand, this is the realm of the individual annotation
libraries, so it isn't even relevent to this convesation. However,
when it is done, a specific type to represent the concept would be
more prodent. For example, I would like to annotate with listOf(str,
int) or tupleOf(multiple(bool)) to mean "A list of a str and an int"
and "A tuple of muiltple bool objects", respectively.

More information about the Python-3000 mailing list