Python has two kinds of callables: functions and generators/coroutines.
Functions have a two-way exit: return or raise.
Coroutines have a three-way exit: return, yield or raise.
Because generators and coroutines are newer, a lot of the C code in genobject.c, ceval.c and related files squeezes the three-way exit into a two-way exit using StopIteration and StopAsyncIteration which is really clunky and inefficient.
Instead of squeezing three-way exits into two-ways exits, we should be broadening the two-way exits into three-way exits, when needed.
For example, we can drop the throwflag argument from _PyEval_EvalFrameDefault by implementing gen.throw() in bytecode.
We can do this because bytecode already handles the three-way exit in FOR_ITER and SEND as follows:
Of course, we still need to have some C functions, not everything can be done in bytecode.
For those functions, we should use something like the interface of gen_send_ex2 which returns the kind of exit, and uses an out parameter for the value
Python has two kinds of callables: functions and generators/coroutines.
Functions have a two-way exit: return or raise. Coroutines have a three-way exit: return, yield or raise.
Because generators and coroutines are newer, a lot of the C code in genobject.c, ceval.c and related files squeezes the three-way exit into a two-way exit using
StopIteration
andStopAsyncIteration
which is really clunky and inefficient.Instead of squeezing three-way exits into two-ways exits, we should be broadening the two-way exits into three-way exits, when needed.
For example, we can drop the
throwflag
argument from_PyEval_EvalFrameDefault
by implementinggen.throw()
in bytecode. We can do this because bytecode already handles the three-way exit inFOR_ITER
andSEND
as follows:gen.send()
can be implemented as something like:gen.throw()
, etc. can be implemented similarly. See https://github.com/faster-cpython/ideas/issues/67#issuecomment-1004866159Of course, we still need to have some C functions, not everything can be done in bytecode. For those functions, we should use something like the interface of
gen_send_ex2
which returns the kind of exit, and uses an out parameter for the value