Coroutines might be considered severe competitors of ordinary functions. After
all, there's no repeated stack handling required between successive
activations: tt(co_yields) simply suspend coroutines, leaving all their data,
ready to be (re)used, in the heap.

In many situations coroutines are considered more attractive at an intuitive
level: already in the introductory section of this chapter they were
characterized as em(cooperating routines), where the coroutine cooperates with
its caller, producing the caller's requested information as if the coroutine
is part of the caller's code. But although it formally isn't it em(can)
conceptually be considered part of the caller's code, as it doesn't have to be
called again and again during the caller's lifetime: once activated the
coroutine remains available in memory and doesn't have to be called again when
it's resumed. Coroutines are em(cooperating) in that sense: they can in fact
be considered part of the caller's code. In this way they really differ from
independent functions which, when called repeatedly, are called again and
again `from scratch', implying intensive stack operations.

On the other hand, using coroutines is way more complex than using
`traditional' functions. The source files of the discussed tt(Dir) class
required some 100 lines of source code, whereas the coroutine based
implementation needed about 700 lines of code. But maybe that's not a fair
comparison. Maybe the tt(cppcoro) library's sources shouldn't be considered,
like when we're using --say-- strings, streams and vectors, in which case we
also ignore the sizes of their sources when they're used in our programs. If
we em(do) ignore the sizes of tt(cppcoro's) sources, then the coroutine based
implementation in fact requires em(fewer) lines of code than the tt(Dir)
class, as the tt(Generator) and tt(RecursiveGenerator) handler classes are
provided by the tt(cppcoro) library.

Eventually, implementing parts of algorithms with coroutines, instead of using
the (functions based) structured programming approach, might simply be a
matter of taste. But maybe, as coroutines allow us to split up algorithms in
separate parts which are not using stack-based activations, the efficiency of
coroutine-based implementations exceeds the efficiency of implementations
using separate supoprt functions. To get some information about the efficiency
of programs using coroutines vs. programs that use separate support functions
the tt(class Dir) based program and the tt(coroDir) based program was each run
five times, processing a large multi-directory, multi-file structure,
containing over 400.000 entries. The execution times of each of the five runs
are highly comparable. The following table shows the average clock-times, the
average user-times, and the average system-times for the tt(class Dir) based
program and the tt(coroDir) based program:

center(
    tbl(rcccc)(
        tline()()
        tr(tnc(2)()                 tnc(3)(time))
        tline(3)(5)
        tr(tc()          tc()       tc(real) tc(user)    tc(system))
        tline(1)(5)
        tr(tc(class Dir) tc(nbsp()) tc(82)  tc(22)      tc(59))
        tr(tc(coroDir)   tc()       tc(88)  tc(25)      tc(62))
        tline(1)(5)
    )
  )
    Although the tt(class Dir) implementation uses slightly less time than the
tt(coroDir) implementatin, the differences are small, and should not be
interpreted as an indication that (maybe different from what was expected)
coroutine based implementations are inherently slower than function based
implementations. Furthermore, coroutines themselves often call ordinary
functions (like tt(readdir) called by tt(coroDir's ) coroutine
tt(dirEntries)), which still require stack-handling.

The conclusion at the end of this chapter is therefore that, yes, coroutines
are available in bf(C++), but they require lots of effort before they can be
used.  Some libraries (like tt(cppcoro)) are available, but they're not (yet?)
part of the software that comes standard with your bf(C++) compiler.  However,
the underlying philosophy (being able to use cooperating routines) certainly
is attractive, although it doesn't necessarily result in more efficient
programs than programs which are developed using the traditional structured
programming approach. And so, in the end, whether or not to use coroutines
might simply boil down to a matter of taste.
