Formatting fixes; use "::" shortcuts.

This commit is contained in:
Georg Brandl 2011-10-30 12:46:47 +01:00
parent 7a9f081882
commit 51e68d9af8
1 changed files with 44 additions and 51 deletions

View File

@ -14,16 +14,17 @@ Post-History:
Abstract
========
A syntax is proposed for defining and calling a special type of generator
called a 'cofunction'. It is designed to provide a streamlined way of
writing generator-based coroutines, and allow the early detection of
certain kinds of error that are easily made when writing such code, which
otherwise tend to cause hard-to-diagnose symptoms.
A syntax is proposed for defining and calling a special type of
generator called a 'cofunction'. It is designed to provide a
streamlined way of writing generator-based coroutines, and allow the
early detection of certain kinds of error that are easily made when
writing such code, which otherwise tend to cause hard-to-diagnose
symptoms.
This proposal builds on the 'yield from' mechanism described in PEP 380,
and describes some of the semantics of cofunctions in terms of it. However,
it would be possible to define and implement cofunctions independently of
PEP 380 if so desired.
This proposal builds on the 'yield from' mechanism described in PEP
380, and describes some of the semantics of cofunctions in terms of
it. However, it would be possible to define and implement cofunctions
independently of PEP 380 if so desired.
Specification
@ -32,29 +33,26 @@ Specification
Cofunction definitions
----------------------
A new keyword ``codef`` is introduced which is used in place of ``def`` to
define a cofunction. A cofunction is a special kind of generator having the
following characteristics:
A new keyword ``codef`` is introduced which is used in place of
``def`` to define a cofunction. A cofunction is a special kind of
generator having the following characteristics:
1. A cofunction is always a generator, even if it does not contain any
1. A cofunction is always a generator, even if it does not contain any
``yield`` or ``yield from`` expressions.
2. A cofunction cannot be called the same way as an ordinary function. An
exception is raised if an ordinary call to a cofunction is attempted.
2. A cofunction cannot be called the same way as an ordinary function.
An exception is raised if an ordinary call to a cofunction is
attempted.
Cocalls
-------
Calls from one cofunction to another are made by marking the call with
a new keyword ``cocall``. The expression
::
a new keyword ``cocall``. The expression ::
cocall f(*args, **kwds)
is semantically equivalent to
::
is semantically equivalent to ::
yield from f.__cocall__(*args, **kwds)
@ -62,48 +60,43 @@ except that the object returned by __cocall__ is expected to be an
iterator, so the step of calling iter() on it is skipped.
The full syntax of a cocall expression is described by the following
grammar lines:
::
grammar lines::
atom: cocall | <existing alternatives for atom>
cocall: 'cocall' atom cotrailer* '(' [arglist] ')'
cotrailer: '[' subscriptlist ']' | '.' NAME
The ``cocall`` keyword is syntactically valid only inside a cofunction.
A SyntaxError will result if it is used in any other context.
The ``cocall`` keyword is syntactically valid only inside a
cofunction. A SyntaxError will result if it is used in any other
context.
Objects which implement __cocall__ are expected to return an object
obeying the iterator protocol. Cofunctions respond to __cocall__ the
obeying the iterator protocol. Cofunctions respond to __cocall__ the
same way as ordinary generator functions respond to __call__, i.e. by
returning a generator-iterator.
Certain objects that wrap other callable objects, notably bound methods,
will be given __cocall__ implementations that delegate to the underlying
object.
Certain objects that wrap other callable objects, notably bound
methods, will be given __cocall__ implementations that delegate to the
underlying object.
New builtins, attributes and C API functions
--------------------------------------------
To facilitate interfacing cofunctions with non-coroutine code, there will
be a built-in function ``costart`` whose definition is equivalent to
::
be a built-in function ``costart`` whose definition is equivalent to ::
def costart(obj, *args, **kwds):
return obj.__cocall__(*args, **kwds)
There will also be a corresponding C API function
::
There will also be a corresponding C API function ::
PyObject *PyObject_CoCall(PyObject *obj, PyObject *args, PyObject *kwds)
It is left unspecified for now whether a cofunction is a distinct type
of object or, like a generator function, is simply a specially-marked
function instance. If the latter, a read-only boolean attribute
``__iscofunction__`` should be provided to allow testing whether a given
function object is a cofunction.
function instance. If the latter, a read-only boolean attribute
``__iscofunction__`` should be provided to allow testing whether a
given function object is a cofunction.
Motivation and Rationale
@ -111,32 +104,32 @@ Motivation and Rationale
The ``yield from`` syntax is reasonably self-explanatory when used for
the purpose of delegating part of the work of a generator to another
function. It can also be used to good effect in the implementation of
function. It can also be used to good effect in the implementation of
generator-based coroutines, but it reads somewhat awkwardly when used
for that purpose, and tends to obscure the true intent of the code.
Furthermore, using generators as coroutines is somewhat error-prone.
If one forgets to use ``yield from`` when it should have been used,
or uses it when it shouldn't have, the symptoms that result can be
If one forgets to use ``yield from`` when it should have been used, or
uses it when it shouldn't have, the symptoms that result can be
obscure and confusing.
Finally, sometimes there is a need for a function to be a coroutine
even though it does not yield anything, and in these cases it is
necessary to resort to kludges such as ``if 0: yield`` to force it
to be a generator.
necessary to resort to kludges such as ``if 0: yield`` to force it to
be a generator.
The ``codef`` and ``cocall`` constructs address the first issue by
making the syntax directly reflect the intent, that is, that the
function forms part of a coroutine.
The second issue is addressed
by making it impossible to mix coroutine and non-coroutine code in
ways that don't make sense. If the rules are violated, an exception
is raised that points out exactly what and where the problem is.
The second issue is addressed by making it impossible to mix coroutine
and non-coroutine code in ways that don't make sense. If the rules
are violated, an exception is raised that points out exactly what and
where the problem is.
Lastly, the need for dummy yields is eliminated by making the
form of definition determine whether the function is a coroutine,
rather than what it contains.
Lastly, the need for dummy yields is eliminated by making the form of
definition determine whether the function is a coroutine, rather than
what it contains.
Prototype Implementation