<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>p1053R0: Future-proofing continuations for executors</title>
<style data-fill-with="stylesheet">/******************************************************************************
 *                   Style sheet for the W3C specifications                   *
 *
 * Special classes handled by this style sheet include:
 *
 * Indices
 *   - .toc for the Table of Contents (<ol class="toc">)
 *     + <span class="secno"> for the section numbers
 *   - #toc for the Table of Contents (<nav id="toc">)
 *   - ul.index for Indices (<a href="#ref">term</a><span>, in §N.M</span>)
 *   - table.index for Index Tables (e.g. for properties or elements)
 *
 * Structural Markup
 *   - table.data for general data tables
 *     -> use 'scope' attribute, <colgroup>, <thead>, and <tbody> for best results !
 *     -> use <table class='complex data'> for extra-complex tables
 *     -> use <td class='long'> for paragraph-length cell content
 *     -> use <td class='pre'> when manual line breaks/indentation would help readability
 *   - dl.switch for switch statements
 *   - ol.algorithm for algorithms (helps to visualize nesting)
 *   - .figure and .caption (HTML4) and figure and figcaption (HTML5)
 *     -> .sidefigure for right-floated figures
 *   - ins/del
 *
 * Code
 *   - pre and code
 *
 * Special Sections
 *   - .note       for informative notes             (div, p, span, aside, details)
 *   - .example    for informative examples          (div, p, pre, span)
 *   - .issue      for issues                        (div, p, span)
 *   - .assertion  for assertions                    (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *
 * Definition Boxes
 *   - pre.def   for WebIDL definitions
 *   - table.def for tables that define other entities (e.g. CSS properties)
 *   - dl.def    for definition lists that define other entitles (e.g. HTML elements)
 *
 * Numbering
 *   - .secno for section numbers in .toc and headings (<span class='secno'>3.2</span>)
 *   - .marker for source-inserted example/figure/issue numbers (<span class='marker'>Issue 4</span>)
 *   - ::before styled for CSS-generated issue/example/figure numbers:
 *     -> Documents wishing to use this only need to add
 *        figcaption::before,
 *        .caption::before { content: "Figure "  counter(figure) " ";  }
 *        .example::before { content: "Example " counter(example) " "; }
 *        .issue::before   { content: "Issue "   counter(issue) " ";   }
 *
 * Header Stuff (ignore, just don't conflict with these classes)
 *   - .head for the header
 *   - .copyright for the copyright
 *
 * Miscellaneous
 *   - .overlarge for things that should be as wide as possible, even if
 *     that overflows the body text area. This can be used on an item or
 *     on its container, depending on the effect desired.
 *     Note that this styling basically doesn't help at all when printing,
 *     since A4 paper isn't much wider than the max-width here.
 *     It's better to design things to fit into a narrower measure if possible.
 *   - js-added ToC jump links (see fixup.js)
 *
 ******************************************************************************/

/******************************************************************************/
/*                                   Body                                     */
/******************************************************************************/

	body {
		counter-reset: example figure issue;

		/* Layout */
		max-width: 50em;               /* limit line length to 50em for readability   */
		margin: 0 auto;                /* center text within page                     */
		padding: 1.6em 1.5em 2em 50px; /* assume 16px font size for downlevel clients */
		padding: 1.6em 1.5em 2em calc(26px + 1.5em); /* leave space for status flag     */

		/* Typography */
		line-height: 1.5;
		font-family: sans-serif;
		widows: 2;
		orphans: 2;
		word-wrap: break-word;
		overflow-wrap: break-word;
		hyphens: auto;

		/* Colors */
		color: black;
		background: white top left fixed no-repeat;
		background-size: 25px auto;
	}


/******************************************************************************/
/*                         Front Matter & Navigation                          */
/******************************************************************************/

/** Header ********************************************************************/

	div.head { margin-bottom: 1em }
	div.head hr { border-style: solid; }

	div.head h1 {
		font-weight: bold;
		margin: 0 0 .1em;
		font-size: 220%;
	}

	div.head h2 { margin-bottom: 1.5em;}

/** W3C Logo ******************************************************************/

	.head .logo {
		float: right;
		margin: 0.4rem 0 0.2rem .4rem;
	}

	.head img[src*="logos/W3C"] {
		display: block;
		border: solid #1a5e9a;
		border-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		color: white;
		font-weight: bold;
	}

	.head a:hover > img[src*="logos/W3C"],
	.head a:focus > img[src*="logos/W3C"] {
		opacity: .8;
	}

	.head a:active > img[src*="logos/W3C"] {
		background: #c00;
		border-color: #c00;
	}

	/* see also additional rules in Link Styling section */

/** Copyright *****************************************************************/

	p.copyright,
	p.copyright small { font-size: small }

/** Back to Top / ToC Toggle **************************************************/

	@media print {
		#toc-nav {
			display: none;
		}
	}
	@media not print {
		#toc-nav {
			position: fixed;
			z-index: 2;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
			color: black;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

			height: 1.33em;
			padding: .1em 0.3em;
			margin: 0;

			background: white;
			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;
			background: white;
		}
		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		#toc-nav > a:hover,
		#toc-nav > a:focus {
			background: #f8f8f8;
		}
		#toc-nav > a:not(:hover):not(:focus) {
			color: #707070;
		}

		/* statusbar gets in the way on keyboard focus; remove once browsers fix */
		#toc-nav > a[href="#toc"]:not(:hover):focus:last-child {
			padding-bottom: 1.5rem;
		}

		#toc-nav:not(:hover) > a:not(:focus) > span + span {
			/* Ideally this uses :focus-within on #toc-nav */
			display: none;
		}
		#toc-nav > a > span + span {
			padding-right: 0.2em;
		}

		#toc-toggle-inline {
			vertical-align: 0.05em;
			font-size: 80%;
			color: gray;
			color: hsla(203,20%,40%,.7);
			border-style: none;
			background: transparent;
			position: relative;
		}
		#toc-toggle-inline:hover:not(:active),
		#toc-toggle-inline:focus:not(:active) {
			text-shadow: 1px 1px silver;
			top: -1px;
			left: -1px;
		}

		#toc-nav :active {
			color: #C00;
		}
	}

/** ToC Sidebar ***************************************************************/

	/* Floating sidebar */
	@media screen {
		body.toc-sidebar #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			max-width: 80%;
			max-width: calc(100% - 2em - 26px);
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
		}
		body.toc-sidebar #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
		}
		body.toc-sidebar #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	/* Hide main scroller when only the ToC is visible anyway */
	@media screen and (max-width: 28em) {
		body.toc-sidebar {
			overflow: hidden;
		}
	}

	/* Sidebar with its own space */
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
		}
		body:not(.toc-inline) #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
		}

		body:not(.toc-inline) {
			padding-left: 29em;
		}
		/* See also Overflow section at the bottom */

		body:not(.toc-inline) #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) {
			margin: 0 4em;
		}
	}

/******************************************************************************/
/*                                Sectioning                                  */
/******************************************************************************/

/** Headings ******************************************************************/

	h1, h2, h3, h4, h5, h6, dt {
		page-break-after: avoid;
		page-break-inside: avoid;
		font: 100% sans-serif;   /* Reset all font styling to clear out UA styles */
		font-family: inherit;    /* Inherit the font family. */
		line-height: 1.2;        /* Keep wrapped headings compact */
		hyphens: manual;         /* Hyphenated headings look weird */
	}

	h2, h3, h4, h5, h6 {
		margin-top: 3rem;
	}

	h1, h2, h3 {
		color: #005A9C;
		background: transparent;
	}

	h1 { font-size: 170%; }
	h2 { font-size: 140%; }
	h3 { font-size: 120%; }
	h4 { font-weight: bold; }
	h5 { font-style: italic; }
	h6 { font-variant: small-caps; }
	dt { font-weight: bold; }

/** Subheadings ***************************************************************/

	h1 + h2,
	#subtitle {
		/* #subtitle is a subtitle in an H2 under the H1 */
		margin-top: 0;
	}
	h2 + h3,
	h3 + h4,
	h4 + h5,
	h5 + h6 {
		margin-top: 1.2em; /* = 1 x line-height */
	}

/** Section divider ***********************************************************/

	:not(.head) > hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		border: transparent solid 0;
		background: transparent;
	}
	:not(.head) > hr::before {
		content: "\2727\2003\2003\2727\2003\2003\2727";
	}

/******************************************************************************/
/*                            Paragraphs and Lists                            */
/******************************************************************************/

	p {
		margin: 1em 0;
	}

	dd > p:first-child,
	li > p:first-child {
		margin-top: 0;
	}

	ul, ol {
		margin-left: 0;
		padding-left: 2em;
	}

	li {
		margin: 0.25em 0 0.5em;
		padding: 0;
	}

	dl dd {
		margin: 0 0 .5em 2em;
	}

	.head dd + dd { /* compact for header */
		margin-top: -.5em;
	}

	/* Style for algorithms */
	ol.algorithm ol:not(.algorithm),
	.algorithm > ol ol:not(.algorithm) {
	 border-left: 0.5em solid #DEF;
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	  padding: .5em;
	  border: thin solid #ddd; border-radius: .5em;
	  margin: .5em calc(-0.5em - 1px);
	}
	[data-algorithm]:not(.heading) > :first-child {
	  margin-top: 0;
	}
	[data-algorithm]:not(.heading) > :last-child {
	  margin-bottom: 0;
	}

	/* Style for switch/case <dl>s */
	dl.switch > dd > ol.only,
	dl.switch > dd > .only > ol {
	 margin-left: 0;
	}
	dl.switch > dd > ol.algorithm,
	dl.switch > dd > .algorithm > ol {
	 margin-left: -2em;
	}
	dl.switch {
	 padding-left: 2em;
	}
	dl.switch > dt {
	 text-indent: -1.5em;
	 margin-top: 1em;
	}
	dl.switch > dt + dt {
	 margin-top: 0;
	}
	dl.switch > dt::before {
	 content: '\21AA';
	 padding: 0 0.5em 0 0;
	 display: inline-block;
	 width: 1em;
	 text-align: right;
	 line-height: 0.5em;
	}

/** Terminology Markup ********************************************************/


/******************************************************************************/
/*                                 Inline Markup                              */
/******************************************************************************/

/** Terminology Markup ********************************************************/
	dfn   { /* Defining instance */
		font-weight: bolder;
	}
	a > i { /* Instance of term */
		font-style: normal;
	}
	dt dfn code, code.idl {
		font-size: medium;
	}
	dfn var {
		font-style: normal;
	}

/** Change Marking ************************************************************/

	del { color: red;  text-decoration: line-through; }
	ins { color: #080; text-decoration: underline;    }

/** Miscellaneous improvements to inline formatting ***************************/

	sup {
		vertical-align: super;
		font-size: 80%
	}

/******************************************************************************/
/*                                    Code                                    */
/******************************************************************************/

/** General monospace/pre rules ***********************************************/

	pre, code, samp {
		font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
		font-size: .9em;
		page-break-inside: avoid;
		hyphens: none;
		text-transform: none;
	}
	pre code,
	code code {
		font-size: 100%;
	}

	pre {
		margin-top: 1em;
		margin-bottom: 1em;
		overflow: auto;
	}

/** Inline Code fragments *****************************************************/

  /* Do something nice. */

/******************************************************************************/
/*                                    Links                                   */
/******************************************************************************/

/** General Hyperlinks ********************************************************/

	/* We hyperlink a lot, so make it less intrusive */
	a[href] {
		color: #034575;
		text-decoration: none;
		border-bottom: 1px solid #707070;
		/* Need a bit of extending for it to look okay */
		padding: 0 1px 0;
		margin: 0 -1px 0;
	}
	a:visited {
		border-bottom-color: #BBB;
	}

	/* Use distinguishing colors when user is interacting with the link */
	a[href]:focus,
	a[href]:hover {
		background: #f8f8f8;
		background: rgba(75%, 75%, 75%, .25);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	a[href]:active {
		color: #C00;
		border-color: #C00;
	}

	/* Backout above styling for W3C logo */
	.head .logo,
	.head .logo a {
		border: none;
		text-decoration: none;
		background: transparent;
	}

/******************************************************************************/
/*                                    Images                                  */
/******************************************************************************/

	img {
		border-style: none;
	}

	/* For autogen numbers, add
	   .caption::before, figcaption::before { content: "Figure " counter(figure) ". "; }
	*/

	figure, .figure, .sidefigure {
		page-break-inside: avoid;
		text-align: center;
		margin: 2.5em 0;
	}
	.figure img,    .sidefigure img,    figure img,
	.figure object, .sidefigure object, figure object {
		max-width: 100%;
		margin: auto;
	}
	.figure pre, .sidefigure pre, figure pre {
		text-align: left;
		display: table;
		margin: 1em auto;
	}
	.figure table, figure table {
		margin: auto;
	}
	@media screen and (min-width: 20em) {
		.sidefigure {
			float: right;
			width: 50%;
			margin: 0 0 0.5em 0.5em
		}
	}
	.caption, figcaption, caption {
		font-style: italic;
		font-size: 90%;
	}
	.caption::before, figcaption::before, figcaption > .marker {
		font-weight: bold;
	}
	.caption, figcaption {
		counter-increment: figure;
	}

	/* DL list is indented 2em, but figure inside it is not */
	dd > .figure, dd > figure { margin-left: -2em }

/******************************************************************************/
/*                             Colored Boxes                                  */
/******************************************************************************/

	.issue, .note, .example, .assertion, .advisement, blockquote {
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	.issue,
	.note,
	.example,
	.advisement,
	.assertion,
	blockquote {
		margin: 1em auto;
	}
	.note  > p:first-child,
	.issue > p:first-child,
	blockquote > :first-child {
		margin-top: 0;
	}
	blockquote > :last-child {
		margin-bottom: 0;
	}

/** Blockquotes ***************************************************************/

	blockquote {
		border-color: silver;
	}

/** Open issue ****************************************************************/

	.issue {
		border-color: #E05252;
		background: #FBE9E9;
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		text-transform: uppercase;
		color: #AE1E1E;
		padding-right: 1em;
		text-transform: uppercase;
	}
	/* Add .issue::before { content: "Issue " counter(issue) " "; } for autogen numbers,
	   or use class="marker" to mark up the issue number in source. */

/** Example *******************************************************************/

	.example {
		border-color: #E0CB52;
		background: #FCFAEE;
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		text-transform: uppercase;
		color: #827017;
		min-width: 7.5em;
		display: block;
	}
	/* Add .example::before { content: "Example " counter(example) " "; } for autogen numbers,
	   or use class="marker" to mark up the example number in source. */

/** Non-normative Note ********************************************************/

	.note {
		border-color: #52E052;
		background: #E9FBE9;
		overflow: auto;
	}

	.note::before, .note > .marker,
	details.note > summary::before,
	details.note > summary > .marker {
		text-transform: uppercase;
		display: block;
		color: hsl(120, 70%, 30%);
	}
	/* Add .note::before { content: "Note"; } for autogen label,
	   or use class="marker" to mark up the label in source. */

	details.note > summary {
		display: block;
		color: hsl(120, 70%, 30%);
	}
	details.note[open] > summary {
		border-bottom: 1px silver solid;
	}

/** Assertion Box *************************************************************/
	/*  for assertions in algorithms */

	.assertion {
		border-color: #AAA;
		background: #EEE;
	}

/** Advisement Box ************************************************************/
	/*  for attention-grabbing normative statements */

	.advisement {
		border-color: orange;
		border-style: none solid;
		background: #FFEECC;
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement > .marker {
		color: #B35F00;
	}

/** Spec Obsoletion Notice ****************************************************/
	/* obnoxious obsoletion notice for older/abandoned specs. */

	details {
		display: block;
	}
	summary {
		font-weight: bolder;
	}

	.annoying-warning:not(details),
	details.annoying-warning:not([open]) > summary,
	details.annoying-warning[open] {
		background: #fdd;
		color: red;
		font-weight: bold;
		padding: .75em 1em;
		border: thick red;
		border-style: solid;
		border-radius: 1em;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

@media not print {
	details.annoying-warning[open] {
		position: fixed;
		left: 1em;
		right: 1em;
		bottom: 1em;
		z-index: 1000;
	}
}

	details.annoying-warning:not([open]) > summary {
		text-align: center;
	}

/** Entity Definition Boxes ***************************************************/

	.def {
		padding: .5em 1em;
		background: #DEF;
		margin: 1.2em 0;
		border-left: 0.5em solid #8CCBF2;
	}

/******************************************************************************/
/*                                    Tables                                  */
/******************************************************************************/

	th, td {
		text-align: left;
		text-align: start;
	}

/** Property/Descriptor Definition Tables *************************************/

	table.def {
		/* inherits .def box styling, see above */
		width: 100%;
		border-spacing: 0;
	}

	table.def td,
	table.def th {
		padding: 0.5em;
		vertical-align: baseline;
		border-bottom: 1px solid #bbd7e9;
	}

	table.def > tbody > tr:last-child th,
	table.def > tbody > tr:last-child td {
		border-bottom: 0;
	}

	table.def th {
		font-style: italic;
		font-weight: normal;
		padding-left: 1em;
		width: 3em;
	}

	/* For when values are extra-complex and need formatting for readability */
	table td.pre {
		white-space: pre-wrap;
	}

	/* A footnote at the bottom of a def table */
	table.def           td.footnote {
		padding-top: 0.6em;
	}
	table.def           td.footnote::before {
		content: " ";
		display: block;
		height: 0.6em;
		width: 4em;
		border-top: thin solid;
	}

/** Data tables (and properly marked-up index tables) *************************/
	/*
		 <table class="data"> highlights structural relationships in a table
		 when correct markup is used (e.g. thead/tbody, th vs. td, scope attribute)

		 Use class="complex data" for particularly complicated tables --
		 (This will draw more lines: busier, but clearer.)

		 Use class="long" on table cells with paragraph-like contents
		 (This will adjust text alignment accordingly.)
		 Alternately use class="longlastcol" on tables, to have the last column assume "long".
	*/

	table {
		word-wrap: normal;
		overflow-wrap: normal;
		hyphens: manual;
	}

	table.data,
	table.index {
		margin: 1em auto;
		border-collapse: collapse;
		border: hidden;
		width: 100%;
	}
	table.data caption,
	table.index caption {
		max-width: 50em;
		margin: 0 auto 1em;
	}

	table.data td,  table.data th,
	table.index td, table.index th {
		padding: 0.5em 1em;
		border-width: 1px;
		border-color: silver;
		border-top-style: solid;
	}

	table.data thead td:empty {
		padding: 0;
		border: 0;
	}

	table.data  thead,
	table.index thead,
	table.data  tbody,
	table.index tbody {
		border-bottom: 2px solid;
	}

	table.data colgroup,
	table.index colgroup {
		border-left: 2px solid;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		border-right: 2px solid;
		border-top: 1px solid silver;
		padding-right: 1em;
	}

	table.data th[colspan],
	table.data td[colspan] {
		text-align: center;
	}

	table.complex.data th,
	table.complex.data td {
		border: 1px solid silver;
		text-align: center;
	}

	table.data.longlastcol td:last-child,
	table.data td.long {
	 vertical-align: baseline;
	 text-align: left;
	}

	table.data img {
		vertical-align: middle;
	}


/*
Alternate table alignment rules

	table.data,
	table.index {
		text-align: center;
	}

	table.data  thead th[scope="row"],
	table.index thead th[scope="row"] {
		text-align: right;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		text-align: right;
	}

Possible extra rowspan handling

	table.data  tbody th[rowspan]:not([rowspan='1']),
	table.index tbody th[rowspan]:not([rowspan='1']),
	table.data  tbody td[rowspan]:not([rowspan='1']),
	table.index tbody td[rowspan]:not([rowspan='1']) {
		border-left: 1px solid silver;
	}

	table.data  tbody th[rowspan]:first-child,
	table.index tbody th[rowspan]:first-child,
	table.data  tbody td[rowspan]:first-child,
	table.index tbody td[rowspan]:first-child{
		border-left: 0;
		border-right: 1px solid silver;
	}
*/

/******************************************************************************/
/*                                  Indices                                   */
/******************************************************************************/


/** Table of Contents *********************************************************/

	.toc a {
		/* More spacing; use padding to make it part of the click target. */
		padding-top: 0.1rem;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Reverse color scheme */
		color: black;
		border-color: #3980B5;
		border-bottom-width: 3px !important;
		margin-bottom: 0px !important;
	}
	.toc a:visited {
		border-color: #054572;
	}
	.toc a:not(:focus):not(:hover) {
		/* Allow colors to cascade through from link styling */
		border-bottom-color: transparent;
	}

	.toc, .toc ol, .toc ul, .toc li {
		list-style: none; /* Numbers must be inlined into source */
		/* because generated content isn't search/selectable and markers can't do multilevel yet */
		margin:  0;
		padding: 0;
		line-height: 1.1rem; /* consistent spacing */
	}

	/* ToC not indented until third level, but font style & margins show hierarchy */
	.toc > li             { font-weight: bold;   }
	.toc > li li          { font-weight: normal; }
	.toc > li li li       { font-size:   95%;    }
	.toc > li li li li    { font-size:   90%;    }
	.toc > li li li li li { font-size:   85%;    }

	.toc > li             { margin: 1.5rem 0;    }
	.toc > li li          { margin: 0.3rem 0;    }
	.toc > li li li       { margin-left: 2rem;   }

	/* Section numbers in a column of their own */
	.toc .secno {
		float: left;
		width: 4rem;
		white-space: nowrap;
	}
	.toc > li li li li .secno {
		font-size: 85%;
	}
	.toc > li li li li li .secno {
		font-size: 100%;
	}

	:not(li) > .toc              { margin-left:  5rem; }
	.toc .secno                  { margin-left: -5rem; }
	.toc > li li li .secno       { margin-left: -7rem; }
	.toc > li li li li .secno    { margin-left: -9rem; }
	.toc > li li li li li .secno { margin-left: -11rem; }

	/* Tighten up indentation in narrow ToCs */
	@media (max-width: 30em) {
		:not(li) > .toc              { margin-left:  4rem; }
		.toc .secno                  { margin-left: -4rem; }
		.toc > li li li              { margin-left:  1rem; }
		.toc > li li li .secno       { margin-left: -5rem; }
		.toc > li li li li .secno    { margin-left: -6rem; }
		.toc > li li li li li .secno { margin-left: -7rem; }
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) :not(li) > .toc              { margin-left:  4rem; }
		body:not(.toc-inline) .toc .secno                  { margin-left: -4rem; }
		body:not(.toc-inline) .toc > li li li              { margin-left:  1rem; }
		body:not(.toc-inline) .toc > li li li .secno       { margin-left: -5rem; }
		body:not(.toc-inline) .toc > li li li li .secno    { margin-left: -6rem; }
		body:not(.toc-inline) .toc > li li li li li .secno { margin-left: -7rem; }
	}
	body.toc-sidebar #toc :not(li) > .toc              { margin-left:  4rem; }
	body.toc-sidebar #toc .toc .secno                  { margin-left: -4rem; }
	body.toc-sidebar #toc .toc > li li li              { margin-left:  1rem; }
	body.toc-sidebar #toc .toc > li li li .secno       { margin-left: -5rem; }
	body.toc-sidebar #toc .toc > li li li li .secno    { margin-left: -6rem; }
	body.toc-sidebar #toc .toc > li li li li li .secno { margin-left: -7rem; }

	.toc li {
		clear: both;
	}


/** Index *********************************************************************/

	/* Index Lists: Layout */
	ul.index       { margin-left: 0; columns: 15em; text-indent: 1em hanging; }
	ul.index li    { margin-left: 0; list-style: none; break-inside: avoid; }
	ul.index li li { margin-left: 1em }
	ul.index dl    { margin-top: 0; }
	ul.index dt    { margin: .2em 0 .2em 20px;}
	ul.index dd    { margin: .2em 0 .2em 40px;}
	/* Index Lists: Typography */
	ul.index ul,
	ul.index dl { font-size: smaller; }
	@media not print {
		ul.index li span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
		}
	}

/** Index Tables *****************************************************/
	/* See also the data table styling section, which this effectively subclasses */

	table.index {
		font-size: small;
		border-collapse: collapse;
		border-spacing: 0;
		text-align: left;
		margin: 1em 0;
	}

	table.index td,
	table.index th {
		padding: 0.4em;
	}

	table.index tr:hover td:not([rowspan]),
	table.index tr:hover th:not([rowspan]) {
		background: #f7f8f9;
	}

	/* The link in the first column in the property table (formerly a TD) */
	table.index th:first-child a {
		font-weight: bold;
	}

/******************************************************************************/
/*                                    Print                                   */
/******************************************************************************/

	@media print {
		/* Pages have their own margins. */
		html {
			margin: 0;
		}
		/* Serif for print. */
		body {
			font-family: serif;
		}
	}
	@page {
		margin: 1.5cm 1.1cm;
	}

/******************************************************************************/
/*                                    Legacy                                  */
/******************************************************************************/

	/* This rule is inherited from past style sheets. No idea what it's for. */
	.hide { display: none }



/******************************************************************************/
/*                             Overflow Control                               */
/******************************************************************************/

	.figure .caption, .sidefigure .caption, figcaption {
		/* in case figure is overlarge, limit caption to 50em */
		max-width: 50rem;
		margin-left: auto;
		margin-right: auto;
	}
	.overlarge > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-left: calc(13px + 26.5rem - 50vw);
			margin-right: calc(13px + 26.5rem - 50vw);
			max-width: none;
		}
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) .overlarge {
			/* 30.5em body padding 50em content area */
			margin-left: calc(40em - 50vw) !important;
			margin-right: calc(40em - 50vw) !important;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) .overlarge {
			/* 4em html margin 30.5em body padding 50em content area */
			margin-left: 0 !important;
			margin-right: calc(84.5em - 100vw) !important;
		}
	}

	@media not print {
		.overlarge {
			overflow-x: auto;
			/* See Lea Verou's explanation background-attachment:
			 * http://lea.verou.me/2012/04/background-attachment-local/
			 *
			background: top left  / 4em 100% linear-gradient(to right,  #ffffff, rgba(255, 255, 255, 0)) local,
			            top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local,
			            top left  / 1em 100% linear-gradient(to right,  #c3c3c5, rgba(195, 195, 197, 0)) scroll,
			            top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll,
			            white;
			background-repeat: no-repeat;
			*/
		}
	}
</style>
<style type="text/css">
    table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
      vertical-align: top;
    }
    th, td {
      border-left: none;
      border-right: none;
      padding: 0px 10px;
    }
    th {
      text-align: center;
    }
  </style>
  <meta content="Bikeshed version 374411ba509d23f8a91b3530bae1f342eb291098" name="generator">
  <link href="https://wg21.link/P1053" rel="canonical">
  <meta content="a053bef1144f5bd4ca8ca20fd19544786a235596" name="document-revision">
<style>/* style-md-lists */

/* This is a weird hack for me not yet following the commonmark spec
   regarding paragraph and lists. */
[data-md] > :first-child {
    margin-top: 0;
}
[data-md] > :last-child {
    margin-bottom: 0;
}</style>
<style>/* style-counters */

body {
    counter-reset: example figure issue;
}
.issue {
    counter-increment: issue;
}
.issue:not(.no-marker)::before {
    content: "Issue " counter(issue);
}

.example {
    counter-increment: example;
}
.example:not(.no-marker)::before {
    content: "Example " counter(example);
}
.invalid.example:not(.no-marker)::before,
.illegal.example:not(.no-marker)::before {
    content: "Invalid Example" counter(example);
}

figcaption {
    counter-increment: figure;
}
figcaption:not(.no-marker)::before {
    content: "Figure " counter(figure) " ";
}</style>
<style>/* style-syntax-highlighting */

.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }
.highlight .c { color: #708090 } /* Comment */
.highlight .k { color: #990055 } /* Keyword */
.highlight .l { color: #000000 } /* Literal */
.highlight .n { color: #0077aa } /* Name */
.highlight .o { color: #999999 } /* Operator */
.highlight .p { color: #999999 } /* Punctuation */
.highlight .cm { color: #708090 } /* Comment.Multiline */
.highlight .cp { color: #708090 } /* Comment.Preproc */
.highlight .c1 { color: #708090 } /* Comment.Single */
.highlight .cs { color: #708090 } /* Comment.Special */
.highlight .kc { color: #990055 } /* Keyword.Constant */
.highlight .kd { color: #990055 } /* Keyword.Declaration */
.highlight .kn { color: #990055 } /* Keyword.Namespace */
.highlight .kp { color: #990055 } /* Keyword.Pseudo */
.highlight .kr { color: #990055 } /* Keyword.Reserved */
.highlight .kt { color: #990055 } /* Keyword.Type */
.highlight .ld { color: #000000 } /* Literal.Date */
.highlight .m { color: #000000 } /* Literal.Number */
.highlight .s { color: #a67f59 } /* Literal.String */
.highlight .na { color: #0077aa } /* Name.Attribute */
.highlight .nc { color: #0077aa } /* Name.Class */
.highlight .no { color: #0077aa } /* Name.Constant */
.highlight .nd { color: #0077aa } /* Name.Decorator */
.highlight .ni { color: #0077aa } /* Name.Entity */
.highlight .ne { color: #0077aa } /* Name.Exception */
.highlight .nf { color: #0077aa } /* Name.Function */
.highlight .nl { color: #0077aa } /* Name.Label */
.highlight .nn { color: #0077aa } /* Name.Namespace */
.highlight .py { color: #0077aa } /* Name.Property */
.highlight .nt { color: #669900 } /* Name.Tag */
.highlight .nv { color: #222222 } /* Name.Variable */
.highlight .ow { color: #999999 } /* Operator.Word */
.highlight .mb { color: #000000 } /* Literal.Number.Bin */
.highlight .mf { color: #000000 } /* Literal.Number.Float */
.highlight .mh { color: #000000 } /* Literal.Number.Hex */
.highlight .mi { color: #000000 } /* Literal.Number.Integer */
.highlight .mo { color: #000000 } /* Literal.Number.Oct */
.highlight .sb { color: #a67f59 } /* Literal.String.Backtick */
.highlight .sc { color: #a67f59 } /* Literal.String.Char */
.highlight .sd { color: #a67f59 } /* Literal.String.Doc */
.highlight .s2 { color: #a67f59 } /* Literal.String.Double */
.highlight .se { color: #a67f59 } /* Literal.String.Escape */
.highlight .sh { color: #a67f59 } /* Literal.String.Heredoc */
.highlight .si { color: #a67f59 } /* Literal.String.Interpol */
.highlight .sx { color: #a67f59 } /* Literal.String.Other */
.highlight .sr { color: #a67f59 } /* Literal.String.Regex */
.highlight .s1 { color: #a67f59 } /* Literal.String.Single */
.highlight .ss { color: #a67f59 } /* Literal.String.Symbol */
.highlight .vc { color: #0077aa } /* Name.Variable.Class */
.highlight .vg { color: #0077aa } /* Name.Variable.Global */
.highlight .vi { color: #0077aa } /* Name.Variable.Instance */
.highlight .il { color: #000000 } /* Literal.Number.Integer.Long */
</style>
<style>/* style-selflinks */

.heading, .issue, .note, .example, li, dt {
    position: relative;
}
a.self-link {
    position: absolute;
    top: 0;
    left: calc(-1 * (3.5rem - 26px));
    width: calc(3.5rem - 26px);
    height: 2em;
    text-align: center;
    border: none;
    transition: opacity .2s;
    opacity: .5;
}
a.self-link:hover {
    opacity: 1;
}
.heading > a.self-link {
    font-size: 83%;
}
li > a.self-link {
    left: calc(-1 * (3.5rem - 26px) - 2em);
}
dfn > a.self-link {
    top: auto;
    left: auto;
    opacity: 0;
    width: 1.5em;
    height: 1.5em;
    background: gray;
    color: white;
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: black;
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }</style>
<style>/* style-autolinks */

.css.css, .property.property, .descriptor.descriptor {
    color: #005a9c;
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

[data-link-type].production::before,
[data-link-type].production::after,
.prod [data-link-type]::before,
.prod [data-link-type]::after {
    content: "";
}

[data-link-type=element],
[data-link-type=element-attr] {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace;
    font-size: .9em;
}
[data-link-type=element]::before { content: "<" }
[data-link-type=element]::after  { content: ">" }

[data-link-type=biblio] {
    white-space: pre;
}</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">p1053R0<br>Future-proofing continuations for executors</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Published Proposal, <time class="dt-updated" datetime="2018-05-06">6 May 2018</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="https://wg21.link/P1053">https://wg21.link/P1053</a>
     <dt>Authors:
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:lwh@fb.com">Lee Howes</a> (<span class="p-org org">Facebook</span>)
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:eniebler@fb.com">Eric Niebler</a> (<span class="p-org org">Facebook</span>)
     <dt>Audience:
     <dd>SG1, LEWG
     <dt>Project:
     <dd>ISO JTC1/SC22/WG21: Programming Language C++
     <dt>Source:
     <dd><a href="https://github.com/LeeHowes/CPP/blob/master/future_continuation.bs">https://github.com/LeeHowes/CPP/blob/master/future_continuations.bs</a>
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li><a href="#intro"><span class="secno">1</span> <span class="content">Introduction</span></a>
    <li>
     <a href="#require"><span class="secno">2</span> <span class="content">Requirements</span></a>
     <ol class="toc">
      <li><a href="#helper_thenvalue"><span class="secno">2.1</span> <span class="content">then_value</span></a>
      <li><a href="#helper_thenerror"><span class="secno">2.2</span> <span class="content">then_error</span></a>
      <li><a href="#helper_thenvariant"><span class="secno">2.3</span> <span class="content">then_variant</span></a>
      <li><a href="#helper_thenexceptionfilter"><span class="secno">2.4</span> <span class="content">then_value_with_exception_log</span></a>
     </ol>
    <li><a href="#concept"><span class="secno">3</span> <span class="content">Concept</span></a>
    <li>
     <a href="#examples"><span class="secno">4</span> <span class="content">Examples</span></a>
     <ol class="toc">
      <li><a href="#thenvalue_example"><span class="secno">4.1</span> <span class="content">then_value</span></a>
      <li><a href="#thenerror_example"><span class="secno">4.2</span> <span class="content">then_error</span></a>
      <li><a href="#thenvariant_example"><span class="secno">4.3</span> <span class="content">then_variant</span></a>
      <li><a href="#thenvalueloggingerror_example"><span class="secno">4.4</span> <span class="content">then_value_logging_error</span></a>
     </ol>
    <li><a href="#noexcept"><span class="secno">5</span> <span class="content">Noexcept</span></a>
    <li><a href="#bulk"><span class="secno">6</span> <span class="content">Rethinking bulk execution</span></a>
    <li>
     <a href="#wording"><span class="secno">7</span> <span class="content">Proposed New Wording for P0443</span></a>
     <ol class="toc">
      <li><a href="#promiserequire"><span class="secno">7.1</span> <span class="content"><code class="highlight"><span class="n">Promise</span></code> requirements</span></a>
      <li><a href="#onewayrequire"><span class="secno">7.2</span> <span class="content">OneWayFutureContinuation requirements</span></a>
      <li><a href="#twowayrequire"><span class="secno">7.3</span> <span class="content">TwoWayFutureContinuation requirements</span></a>
      <li><a href="#thenrequire"><span class="secno">7.4</span> <span class="content">ThenFutureContinuation requirements</span></a>
      <li><a href="#onewaychanges"><span class="secno">7.5</span> <span class="content">Changes to OneWayExecutor requirements</span></a>
      <li><a href="#twowaychanges"><span class="secno">7.6</span> <span class="content">Changes to TwoWayExecutor requirements</span></a>
      <li><a href="#thenchanges"><span class="secno">7.7</span> <span class="content">Changes to ThenExecutor requirements</span></a>
      <li><a href="#bulkchanges"><span class="secno">7.8</span> <span class="content">Changes to Bulk requirements in general</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <p>Contributors:</p>
   <ul>
    <li data-md="">
     <p>Jay      Feldblum</p>
    <li data-md="">
     <p>Andrii   Grynenko</p>
    <li data-md="">
     <p>Kirk     Shoop</p>
   </ul>
   <h2 class="heading settled" data-level="1" id="intro"><span class="secno">1. </span><span class="content">Introduction</span><a class="self-link" href="#intro"></a></h2>
    <a href="https://wg21.link/P0443">p0443</a> defines interfaces for executors and the
continuation functions passed to them. <a href="https://wg21.link/P1054">p1054</a> utilises these fundamental interfaces to build
expressive concepts for future types where continuations are cleanly mapped
through continuation construction functions. 
   <p>The current design of the continuation functions passed to then_execute are
based on the ability of the executor to invoke the continuation.</p>
   <p>In essence the continuations have an interface similar to:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="n">R</span> <span class="k">operator</span><span class="p">()(</span><span class="n">T</span><span class="p">);</span>
  <span class="n">R</span> <span class="nf">operator</span><span class="p">()(</span><span class="n">exception_arg</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span>
<span class="p">};</span>
</pre>
   <p>where either function is optional, and in that situation the other operation will act as a passthrough.
One reason for designing the API in this way is to allow a simple lambda function to be passed to <code class="highlight"><span class="n">then_execute</span></code>:</p>
<pre class="highlight"><span class="n">e</span><span class="p">.</span><span class="n">then_execute</span><span class="p">([](</span><span class="n">T</span> <span class="n">value</span><span class="p">){</span><span class="k">return</span> <span class="n">value</span><span class="p">;},</span> <span class="n">input_future</span><span class="p">);</span>
</pre>
   <p>The downsides of this design are twofold:</p>
   <ul>
    <li data-md="">
     <p>The description of the continuation is based on ability to invoke it. There is then potential for errors that would easily slip through code review, and silently cause unexpected runtime behaviour.</p>
    <li data-md="">
     <p>The mechanism of describing the continuation with two parallel end-to-end data paths removes the ability to catch and pass an exception from the value operator, or to log and passthrough an exception from the exception operator without rethrowing the exception.</p>
   </ul>
   <p>On the first point, consider the following struct that an author might write in an attempt to handle both values and exceptions at some stage in the pipeline:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">value</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">};</span>
</pre>
   <p>This is a trivial example of ignoring the precise exception and attempting to recover.
Note that the reality here, based on the <a href="https://wg21.link/P0443">p0443</a> definition is that the exception function is not callable as the <code class="highlight"><span class="n">EXCEPTIONAL</span></code> case.
It will therefore not be called and an exception will bypass.
In effect, this struct is semantically equivalent to:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">value</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="n">exception_arg</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">rethrow_exception</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">};</span>
</pre>
   <p>where we have silently lost our recovery path and passed the error through with potentially negative consequences.
There is no compilation or runtime error here, and this kind of problem could be hard to catch in code review.</p>
   <p>On the second point, consider an exception handler that only exists to log that an exception reached a point in the stream:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">value</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="n">exception_arg</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Have exception</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">rethrow_exception</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">};</span>
</pre>
   <p>This is an expensive means of doing nothing to the exception.
With potential extensions to <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span></code> that would allow peeking at
the exception without rethrow, for example <a href="https://wg21.link/P1066">p1066</a>,
there is potentially a wide range of optimisations that we lose the ability to
perform.</p>
   <p>What we might prefer, would be to implement this as:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">value</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="k">operator</span><span class="p">()(</span><span class="n">exception_arg</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Have exception</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">e</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">};</span>
</pre>
   <p>but then we lose the ability to recreate the value.</p>
   <p>We consider these two flaws, one of safety and the other of flexibility, as
unfortunate limitations of a low-level API like executors.</p>
   <p>Expected use of <code class="highlight"><span class="n">FutureContinuation</span></code> as discussed in <a href="https://wg21.link/P1054">p1054</a> is
through the use of helper functions such as <code class="highlight"><span class="n">on_value</span></code> and <code class="highlight"><span class="n">on_error</span></code> that take
a constrained callable and return a <code class="highlight"><span class="n">FutureContinuation</span></code>.
With these helper functions, and the clean readable code they lead to, there is
no need to simplify the <code class="highlight"><span class="n">FutureContinuation</span></code> to be a trivial callable, and we
gain a lot of flexibility by consciously deciding to not simplify it in that
way.</p>
   <p>The goal of this paper is to convince the reader that we should solidify the <code class="highlight"><span class="n">FutureContinuation</span></code> with use cases and examples. We then build on this
to demonstrate how bulk execution should be simplified based on similar
properties, without committing to a design. Finally we propose wording changes
to executors to make the changes concrete.</p>
   <p>The same modifications we propose in this paper apply to both <a href="https://wg21.link/P0443">p0443</a> and <a href="https://wg21.link/P1054">p1054</a>.
Uses of the types in <a href="https://wg21.link/P1054">p1054</a> are unaffected but the
description of the calling mechanism, return values of the construction
functions (<code class="highlight"><span class="n">on_value</span></code>, <code class="highlight"><span class="n">on_error</span></code>) and precise semantics would require updates
similar to those we propose for <a href="https://wg21.link/P0443">p0443</a>.</p>
   <h2 class="heading settled" data-level="2" id="require"><span class="secno">2. </span><span class="content">Requirements</span><a class="self-link" href="#require"></a></h2>
    If we look at some example continuation constructions based on those in <a href="https://wg21.link/P1054">p1054</a> we can see what kind of functionality we might want
here. 
   <h3 class="heading settled" data-level="2.1" id="helper_thenvalue"><span class="secno">2.1. </span><span class="content">then_value</span><a class="self-link" href="#helper_thenvalue"></a></h3>
    This is the simple passthrough of the exception, while applying some operation to the value. 
   <p>The callback we expect to create looks like:</p>
<pre class="highlight"><span class="n">then_value</span><span class="p">([](</span><span class="n">T</span> <span class="n">value</span><span class="p">){</span><span class="n">operation</span><span class="p">(</span><span class="n">value</span><span class="p">);});</span>
</pre>
   <p>As a flow diagram, something like:</p>
<pre class="highlight"><span class="n">set_value</span> <span class="o">---------</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----</span> <span class="n">return_value</span>

<span class="n">set_exception</span> <span class="o">-----------------------------</span> <span class="n">return_exception</span>
</pre>
   <h3 class="heading settled" data-level="2.2" id="helper_thenerror"><span class="secno">2.2. </span><span class="content">then_error</span><a class="self-link" href="#helper_thenerror"></a></h3>
    The equivalent where we apply some operation to the exception, but not the value.
A good example of this might be error recovery. Note that in this case we are breaking the exception chain.
The callback we expect to create looks like: 
<pre class="highlight"><span class="n">then_error</span><span class="p">([](</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">){</span>
  <span class="k">try</span> <span class="p">{</span>
   <span class="n">std</span><span class="o">::</span><span class="n">rethrow_exception</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="n">recoverable_exception</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">catch</span><span class="p">(...)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">rethrow_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
  <span class="p">}});</span>
</pre>
   <p>Or:</p>
<pre class="highlight"><span class="n">set_value</span> <span class="o">-------------------------------------------------------/-----</span> <span class="n">return_value</span>
                                            <span class="o">/-----</span> <span class="n">Recover</span> <span class="o">-----/</span>
<span class="n">set_exception</span> <span class="o">-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----</span> <span class="o">|</span>
                                            \<span class="o">-----</span> <span class="n">Do</span> <span class="n">not</span> <span class="n">recover</span> <span class="o">-----</span> <span class="n">return_exception</span>
</pre>
   <p>Note that in this case we rethrow twice. Logically the first is just to check
the exception type. The second is just returning the exception and relying on
external logic to catch as we do not have two outputs in the syntax.
Improvements to <code class="highlight"><span class="n">exception_ptr</span></code> (along the lines of folly’s <a href="https://github.com/facebook/folly/blob/master/folly/ExceptionWrapper.h">exception_wrapper</a> or those proposed in <a href="https://wg21.link/P1066">p1066</a>) could mitigate the first.
Ability to return either an <code class="highlight"><span class="n">exception_ptr</span></code> or a <code class="highlight"><span class="n">T</span></code> from the error case could
remove the second throw.</p>
   <h3 class="heading settled" data-level="2.3" id="helper_thenvariant"><span class="secno">2.3. </span><span class="content">then_variant</span><a class="self-link" href="#helper_thenvariant"></a></h3>
    Here our operation might take a variant of a value and an exception so that we can write a single function that decides what to do:
The callback we expect to create looks like: 
<pre class="highlight"><span class="n">then_variant</span><span class="p">([](</span><span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span> <span class="n">v</span><span class="p">){</span><span class="n">operation</span><span class="p">(</span><span class="n">v</span><span class="p">);});</span>
</pre>
   <p>Diagrammatically:</p>
<pre class="highlight"><span class="n">set_value</span> <span class="o">-----</span>\                             <span class="o">/-----</span> <span class="n">return_value</span>
               <span class="o">|-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----|</span>
<span class="n">set_exception</span> <span class="o">-/</span>                             \<span class="o">-----</span> <span class="n">return_exception</span>
</pre>
   <p>This is a very common pattern in Facebook’s code where <code class="highlight"><span class="n">folly</span><span class="o">::</span><span class="n">Try</span><span class="o">&lt;</span><span class="n">T</span><span class="o">></span></code>, which
carries a value and exception, is the preferred means of parameterising future
continuations.</p>
   <h3 class="heading settled" data-level="2.4" id="helper_thenexceptionfilter"><span class="secno">2.4. </span><span class="content">then_value_with_exception_log</span><a class="self-link" href="#helper_thenexceptionfilter"></a></h3>
    Here we merely log the existence of an error, and pass it through.
We might write this as: 
<pre class="highlight"><span class="n">then_value_with_exception_log</span><span class="p">(</span>
  <span class="p">[](</span><span class="n">T</span> <span class="n">value</span><span class="p">){</span><span class="n">operation</span><span class="p">(</span><span class="n">v</span><span class="p">);},</span>
  <span class="p">[](</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">){</span><span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Have an exception</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span> <span class="n">e</span><span class="p">;});</span>
</pre>
   <p>Here we have a very simple pair of parallel operations:</p>
<pre class="highlight"><span class="n">set_value</span> <span class="o">---------</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----</span> <span class="n">return_value</span>

<span class="n">set_exception</span> <span class="o">-----</span> <span class="n">Log</span> <span class="o">-------------------</span> <span class="n">return_exception</span>
</pre>
   Note though that it relies on allowing return of an <code class="highlight"><span class="n">exception_ptr</span></code> from the
exception path to do this without a throw. 
   <h2 class="heading settled" data-level="3" id="concept"><span class="secno">3. </span><span class="content">Concept</span><a class="self-link" href="#concept"></a></h2>
    As an alternative way of thinking about this problem we should step back and think about what we want from the solution.
Fundamentally, a continuation is a function from a value input or an exceptional input, to a value output or an exceptional output. 
<pre class="highlight"><span class="n">set_value</span> <span class="o">-----</span>\                             <span class="o">/-----</span> <span class="n">return_value</span>
               <span class="o">|-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----|</span>
<span class="n">set_exception</span> <span class="o">-/</span>                             \<span class="o">-----</span> <span class="n">return_exception</span>
</pre>
   <p>This basic structure covers all of the above uses. The question becomes how we can build this in an efficient manner?</p>
   <p>One option is to do what we do in a lot of Facebook’s code, and implement the operation in terms of <code class="highlight"><span class="n">folly</span><span class="o">::</span><span class="n">Try</span><span class="o">&lt;</span><span class="n">T</span><span class="o">></span></code> putting all functionality in the continuation itself.
Unfortunately, it is clumsy to write efficient code that wants to ignore one or other path entirely using this structure. We are forced into the combined structure in the code.</p>
   <p>Abstractly, though, if we assume that these operations are inputs and outputs from some class, we see that the input is a <code class="highlight"><span class="n">Promise</span></code> type:</p>
<pre class="highlight">                                     <span class="o">/-----</span> <span class="n">return_value</span>
<span class="n">Promise</span> <span class="o">-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----|</span>
                                     \<span class="o">-----</span> <span class="n">return_exception</span>
</pre>
   <p>Where a promise is a class concept consisting of two <code class="highlight"><span class="kt">void</span></code>-returning functions: <code class="highlight"><span class="n">set_value</span></code> and <code class="highlight"><span class="n">set_exception</span></code>.</p>
   <p>Taking a further look at this we realise that actually the output path is merely the input to another operation - one owned by the executor itself. So we see another <code class="highlight"><span class="n">Promise</span></code> lying in wait for us:</p>
<pre class="highlight"><span class="n">Promise</span> <span class="o">-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----</span> <span class="n">Promise</span>
</pre>
   <p>Fundamentally, then, each of the continuation constructors should produce
something that has a promise as input, and a promise as output, and where the
value and error operations can be mixed based on the implementation.
This is fully general. Moreover, by requiring that both of these functions be
provided and thus called by the implementation, it is also safe because the
compiler will fail if a function fails to compile.
The <code class="highlight"><span class="n">set_value</span></code> input can map to either the <code class="highlight"><span class="n">return_value</span></code> or <code class="highlight"><span class="n">return_exception</span></code> output, and similarly for the <code class="highlight"><span class="n">set_exception</span></code> input.</p>
   <p>So what does this look like? Because the Promises are both concepts, not types,
we need to be able to generate this code.
The input promise is a feature of the task we construct. This much is simple.
In addition, we need a way to take the output promise as an input. That is, we
need to construct a usable task from some partial task, plus a promise.</p>
   <p>In summary:</p>
   <blockquote>
    <p>The continuation is an object that, when passed a Promise as a parameter
constructs a new object that is itself a Promise.</p>
   </blockquote>
   <h2 class="heading settled" data-level="4" id="examples"><span class="secno">4. </span><span class="content">Examples</span><a class="self-link" href="#examples"></a></h2>
    Let’s take a few examples of what this looks like to implement. 
   <p>Given a continuation provided by some continuation construction function (some
examples of which we see below) and passed to our processing function, we can
use the continuation by:
 1) constructing internal <code class="highlight"><span class="n">Promise</span></code> that is tied to  our output <code class="highlight"><span class="n">Future</span></code> 2) pass the output promise to the continuation as a means of constructing a
       viable promise object.
 3) call the appropriate operation on the input with data from our input <code class="highlight"><span class="n">Future</span></code>.</p>
   <p>In code that general principle looks like:</p>
<pre class="highlight"><span class="n">OutputFuture</span> <span class="nf">process_continuation</span><span class="p">(</span><span class="n">FutureContinuation</span><span class="o">&amp;&amp;</span> <span class="n">continuation</span><span class="p">)</span> <span class="p">{</span>
  <span class="c1">// Construct output promise/future contract</span>
<span class="c1"></span>  <span class="p">[</span><span class="n">outputPromise</span><span class="p">,</span> <span class="n">outputFuture</span><span class="p">]</span> <span class="n">make_promise_contract</span><span class="o">&lt;</span><span class="n">T</span><span class="o">></span><span class="p">();</span>

  <span class="c1">// Construct the input promise by parameterising the continuation with the</span>
<span class="c1"></span>  <span class="c1">// output promise.</span>
<span class="c1"></span>  <span class="k">auto</span> <span class="n">inputPromise</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">continuation</span><span class="p">)(</span><span class="n">outputPromise</span><span class="p">);</span>

  <span class="c1">// Call the appropriate input data path on the input promise</span>
<span class="c1"></span>  <span class="k">if</span><span class="p">(</span><span class="n">have_value</span><span class="p">())</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">inputPromise</span><span class="p">).</span><span class="n">set_value</span><span class="p">(</span><span class="n">value</span><span class="p">());</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">inputPromise</span><span class="p">).</span><span class="n">set_exception</span><span class="p">(</span><span class="n">exception</span><span class="p">());</span>
  <span class="p">}</span>

  <span class="c1">// Return the outputFuture that will include the result of the computation</span>
<span class="c1"></span>  <span class="k">return</span> <span class="n">outputFuture</span><span class="p">;</span>
<span class="p">}</span>
</pre>
   <h3 class="heading settled" data-level="4.1" id="thenvalue_example"><span class="secno">4.1. </span><span class="content">then_value</span><a class="self-link" href="#thenvalue_example"></a></h3>
    <code class="highlight"><span class="n">then_value</span></code> takes a function from a value to a value and, as discussed above,
returns a function that can be passed a Promise, and which constructs a Promise: 
<pre class="highlight"><span class="c1">// F = function(int(int))</span>
<span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">F</span><span class="o">></span>
<span class="k">auto</span> <span class="n">then_value</span><span class="p">(</span><span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">continuationFunction</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">continuationFunction</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">)](</span>
          <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
        <span class="k">using</span> <span class="n">OutputPromiseRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">);</span>
        <span class="k">using</span> <span class="n">OutputPromise</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

        <span class="k">class</span> <span class="nc">InputPromise</span> <span class="p">{</span>
        <span class="k">public</span><span class="o">:</span>
            <span class="n">InputPromise</span><span class="p">(</span>
                <span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">f</span><span class="p">,</span> <span class="n">OutputPromise</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="o">:</span>
                <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">f</span><span class="p">)),</span> <span class="n">outputPromise_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">))</span> <span class="p">{}</span>

            <span class="kt">void</span> <span class="n">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">try</span> <span class="p">{</span>
                    <span class="k">auto</span> <span class="n">resultOfOperation</span> <span class="o">=</span> <span class="n">f_</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">resultOfOperation</span><span class="p">);</span>
                <span class="p">}</span> <span class="k">catch</span> <span class="p">(...)</span> <span class="p">{</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>

            <span class="kt">void</span> <span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">e</span><span class="p">));</span>
            <span class="p">}</span>

        <span class="k">private</span><span class="o">:</span>
            <span class="n">F</span> <span class="n">f_</span><span class="p">;</span>
            <span class="n">OutputPromise</span> <span class="n">outputPromise_</span><span class="p">;</span>
        <span class="p">};</span>

        <span class="k">return</span> <span class="nf">InputPromise</span><span class="p">(</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">));</span>
    <span class="p">};</span>
<span class="p">}</span>
</pre>
   <p>and constructs the continuation as:</p>
<pre class="highlight"><span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">then_value</span><span class="p">([](</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span><span class="k">return</span> <span class="n">x</span><span class="o">*</span><span class="mi">2</span><span class="p">;});</span>
</pre>
   <p>As an example of using these constructs as if as a simple callback, for an
executor that only supports simple callback mechanisms, we can see that all of
this code optimises to nothing
(<a href="https://godbolt.org/g/m3qvoj">https://godbolt.org/g/m3qvoj</a>).</p>
   <h3 class="heading settled" data-level="4.2" id="thenerror_example"><span class="secno">4.2. </span><span class="content">then_error</span><a class="self-link" href="#thenerror_example"></a></h3>
    Here we construct a continuation from a function from exception_ptr to
exception_ptr as a means of only processing our error stream. 
<pre class="highlight"><span class="c1">// F = function(exception_ptr(exception_ptr))</span>
<span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">F</span><span class="o">></span>
<span class="k">auto</span> <span class="n">then_error</span><span class="p">(</span><span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">continuationFunction</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">continuationFunction</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">)](</span>
          <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
        <span class="k">using</span> <span class="n">OutputPromiseRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">);</span>
        <span class="k">using</span> <span class="n">OutputPromise</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

        <span class="k">class</span> <span class="nc">InputPromise</span> <span class="p">{</span>
        <span class="k">public</span><span class="o">:</span>
            <span class="n">InputPromise</span><span class="p">(</span>
                <span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">f</span><span class="p">,</span> <span class="n">OutputPromise</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="o">:</span>
                <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">f</span><span class="p">)),</span> <span class="n">outputPromise_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">))</span> <span class="p">{}</span>

            <span class="kt">void</span> <span class="n">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="kt">void</span> <span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">try</span> <span class="p">{</span>
                    <span class="k">auto</span> <span class="n">resultOfOperation</span> <span class="o">=</span> <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">e</span><span class="p">));</span>
                    <span class="c1">// Set the exception from the return value</span>
<span class="c1"></span>                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">resultOfOperation</span><span class="p">);</span>
                <span class="p">}</span> <span class="k">catch</span> <span class="p">(...)</span> <span class="p">{</span>
                    <span class="c1">// Also catch the error for completeness.</span>
<span class="c1"></span>                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>

        <span class="k">private</span><span class="o">:</span>
            <span class="n">F</span> <span class="n">f_</span><span class="p">;</span>
            <span class="n">OutputPromise</span> <span class="n">outputPromise_</span><span class="p">;</span>
        <span class="p">};</span>

        <span class="k">return</span> <span class="nf">InputPromise</span><span class="p">(</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">));</span>
    <span class="p">};</span>
<span class="p">}</span>
</pre>
   <p>We can construct a simple exception processing continuation as:</p>
<pre class="highlight"><span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">then_error</span><span class="p">([](</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Log!</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span> <span class="n">e</span><span class="p">;});</span>
</pre>
   <p>Note that even here, if we do not end up using the exception path, all of this
optimises away (<a href="https://godbolt.org/g/xRm2oH">https://godbolt.org/g/xRm2oH</a>)</p>
   <h3 class="heading settled" data-level="4.3" id="thenvariant_example"><span class="secno">4.3. </span><span class="content">then_variant</span><a class="self-link" href="#thenvariant_example"></a></h3>
    We can implement a version that passes variants through as: 
<pre class="highlight"><span class="c1">// F = function(variant&lt;int, exception_ptr>(variant&lt;int, exception_ptr>))</span>
<span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">F</span><span class="o">></span>
<span class="k">auto</span> <span class="n">then_variant</span><span class="p">(</span><span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">continuationFunction</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">continuationFunction</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">)](</span>
          <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
        <span class="k">using</span> <span class="n">OutputPromiseRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">);</span>
        <span class="k">using</span> <span class="n">OutputPromise</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

        <span class="k">class</span> <span class="nc">InputPromise</span> <span class="p">{</span>
        <span class="k">public</span><span class="o">:</span>
            <span class="n">InputPromise</span><span class="p">(</span>
                <span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">f</span><span class="p">,</span> <span class="n">OutputPromise</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="o">:</span>
                <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">f</span><span class="p">)),</span> <span class="n">outputPromise_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">))</span> <span class="p">{}</span>

            <span class="kt">void</span> <span class="n">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">apply</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="kt">void</span> <span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">apply</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">e</span><span class="p">));</span>
            <span class="p">}</span>

        <span class="k">private</span><span class="o">:</span>
            <span class="n">F</span> <span class="n">f_</span><span class="p">;</span>
            <span class="n">OutputPromise</span> <span class="n">outputPromise_</span><span class="p">;</span>

            <span class="kt">void</span> <span class="nf">apply</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span> <span class="n">v</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">struct</span> <span class="n">visitor</span> <span class="p">{</span>
                    <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">result</span><span class="p">)</span> <span class="p">{</span>
                        <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">result</span><span class="p">));</span>
                    <span class="p">}</span>
                    <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span>
                        <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">ex</span><span class="p">));</span>
                    <span class="p">}</span>
                    <span class="n">OutputPromise</span><span class="o">&amp;</span> <span class="n">outputPromise_</span><span class="p">;</span>
                <span class="p">};</span>
                <span class="k">try</span> <span class="p">{</span>
                    <span class="k">auto</span> <span class="n">intermediateValue</span> <span class="o">=</span> <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">v</span><span class="p">));</span>
                    <span class="n">std</span><span class="o">::</span><span class="n">visit</span><span class="p">(</span><span class="n">visitor</span><span class="p">{</span><span class="n">outputPromise_</span><span class="p">},</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">intermediateValue</span><span class="p">));</span>
                <span class="p">}</span> <span class="k">catch</span><span class="p">(...)</span> <span class="p">{</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">};</span>

        <span class="k">return</span> <span class="nf">InputPromise</span><span class="p">(</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">));</span>
    <span class="p">};</span>
<span class="p">}</span>
</pre>
   <p>Constructing the continuation with:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">visitor</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span>
    <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">val</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">val</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span>
    <span class="k">operator</span><span class="p">()(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">ex</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">ex</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
<span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">then_variant</span><span class="p">(</span>
    <span class="p">[](</span><span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span> <span class="n">v</span><span class="p">)</span> <span class="o">-></span> <span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">visit</span><span class="p">(</span><span class="n">visitor</span><span class="p">{},</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">v</span><span class="p">));</span>
    <span class="p">});</span>
</pre>
   <p>Again, with use of variants, if we do not actually use the <code class="highlight"><span class="n">exception_ptr</span></code> route
this optimises away
(<a href="https://godbolt.org/g/AZRAeK">https://godbolt.org/g/AZRAeK</a>).</p>
   <h3 class="heading settled" data-level="4.4" id="thenvalueloggingerror_example"><span class="secno">4.4. </span><span class="content">then_value_logging_error</span><a class="self-link" href="#thenvalueloggingerror_example"></a></h3>
    Finally, we can build an operation that takes two functions, where the error
handler simply passes through the exception with logging: 
<pre class="highlight"><span class="c1">// F = function(int(int))</span>
<span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">F</span><span class="p">,</span> <span class="k">typename</span> <span class="n">FE</span><span class="o">></span>
<span class="k">auto</span> <span class="n">then_value_log_exception</span><span class="p">(</span><span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">valueContinuation</span><span class="p">,</span> <span class="n">FE</span><span class="o">&amp;&amp;</span> <span class="n">errorContinuation</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">valueContinuation</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">valueContinuation</span><span class="p">),</span>
            <span class="n">errorContinuation</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">FE</span><span class="o">></span><span class="p">(</span><span class="n">errorContinuation</span><span class="p">)](</span>
          <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
        <span class="k">using</span> <span class="n">OutputPromiseRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">);</span>
        <span class="k">using</span> <span class="n">OutputPromise</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

        <span class="k">class</span> <span class="nc">InputPromise</span> <span class="p">{</span>
        <span class="k">public</span><span class="o">:</span>
            <span class="n">InputPromise</span><span class="p">(</span>
                <span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">f</span><span class="p">,</span> <span class="n">FE</span><span class="o">&amp;&amp;</span> <span class="n">fe</span><span class="p">,</span> <span class="n">OutputPromise</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="o">:</span>
                <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">f</span><span class="p">)),</span> <span class="n">fe_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">fe</span><span class="p">)),</span> <span class="n">outputPromise_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">))</span> <span class="p">{}</span>

            <span class="kt">void</span> <span class="n">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">try</span> <span class="p">{</span>
                    <span class="k">auto</span> <span class="n">resultOfOperation</span> <span class="o">=</span> <span class="n">f_</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">resultOfOperation</span><span class="p">);</span>
                <span class="p">}</span> <span class="k">catch</span> <span class="p">(...)</span> <span class="p">{</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>

            <span class="kt">void</span> <span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">fe_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">e</span><span class="p">)));</span>
            <span class="p">}</span>

        <span class="k">private</span><span class="o">:</span>
            <span class="n">F</span> <span class="n">f_</span><span class="p">;</span>
            <span class="n">FE</span> <span class="n">fe_</span><span class="p">;</span>
            <span class="n">OutputPromise</span> <span class="n">outputPromise_</span><span class="p">;</span>
        <span class="p">};</span>

        <span class="k">return</span> <span class="nf">InputPromise</span><span class="p">(</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">valueContinuation</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">errorContinuation</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">));</span>
    <span class="p">};</span>
<span class="p">}</span>
</pre>
   <p>and where we might construct this as:</p>
<pre class="highlight"><span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">then_value_log_exception</span><span class="p">(</span>
    <span class="p">[](</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span><span class="k">return</span> <span class="n">x</span><span class="o">*</span><span class="mi">2</span><span class="p">;},</span>
    <span class="p">[](</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">){</span><span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Have exception</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span> <span class="n">e</span><span class="p">;});</span>
</pre>
   <p>Note that with improvements to <code class="highlight"><span class="n">exception_ptr</span></code> this is where we could benefit
from snooping on the exception without rethrow, as <code class="highlight"><span class="n">folly</span><span class="o">::</span><span class="n">exception_wrapper</span></code> enables or is proposed in <a href="https://wg21.link/P1066">p1066</a>. Full source example: <a href="https://godbolt.org/g/Xbp5xK">https://godbolt.org/g/Xbp5xK</a>.</p>
   <h2 class="heading settled" data-level="5" id="noexcept"><span class="secno">5. </span><span class="content">Noexcept</span><a class="self-link" href="#noexcept"></a></h2>
   <p>The methods on <code class="highlight"><span class="n">FutureContinuation</span></code> should be noexcept.
Any exception handling should be handled as part of the <code class="highlight"><span class="n">FutureContinuation</span></code> task and passed to the <code class="highlight"><span class="n">set_exception</span></code> output.</p>
   <p>With this change, the executors do not need exception propagation properties,
nor do they need to expose queries that specify what happens when an exception
leaks from a continuation because this cannot happen. This is a considerable
simplification and reduction in committee work that is still in progress.</p>
   <h2 class="heading settled" data-level="6" id="bulk"><span class="secno">6. </span><span class="content">Rethinking bulk execution</span><a class="self-link" href="#bulk"></a></h2>
   <p>We should encode bulk operations as extended continuations.
Bulk execution is a property of a task, not an executor. While we realise that
the executor has influence on how the task runs and where, which may include
how it is compiled to do bulk dispatch, the actual properties of the task
are orthogonal to the API exposed by executors.</p>
   <p>Encoding the bulk functionality as part of the continuation, rather than the
executor API, would allow us to halve the number of executor entry points.
Further, bulk continuations need not be part of the fundamental concepts and
instead we can encode the interface simply as an extended set of task
construction functions as in <a href="https://wg21.link/P1054">p1054</a>.</p>
   <p>We are confident that bulk can be cleanly implemented in this model, but would
want to see implementation work done. In our view, implementation work is
already necessary to give confidence for the bulk implementations in <a href="https://wg21.link/P0443">p0443</a>, particularly for <code class="highlight"><span class="n">bulk_then_execute</span></code>.</p>
   <p>The bulk API can be achieved in multiple ways. <code class="highlight"><span class="n">FutureContinuation</span></code>'s definition
should be extended to map a <code class="highlight"><span class="n">Promise</span></code> to a <code class="highlight"><span class="n">BulkPromise</span></code>.
The interface of <code class="highlight"><span class="n">BulkPromise</span></code> offers multiple options. Let’s assume that we
base them around a task construction function based on the same parameters of <code class="highlight"><span class="n">then_execute</span></code> in <a href="https://wg21.link/P0443">p0443</a>:</p>
<pre class="highlight"><span class="n">FutureContinuation</span> <span class="nf">bulk_then_value</span><span class="p">(</span><span class="n">F</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">RF</span><span class="p">,</span> <span class="n">SF</span><span class="p">);</span>
</pre>
   <p>One implementation option is that we allow <code class="highlight"><span class="n">set_value</span></code> and <code class="highlight"><span class="n">set_exception</span></code> to
be called multiple times, encapsulating the shape and a completion signal in the
API of the continuation.</p>
   <p>For example:</p>
<pre class="highlight"><span class="kt">void</span> <span class="nf">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">idx</span><span class="p">,</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">value</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">set_exception</span><span class="p">(</span><span class="kt">int</span> <span class="n">idx</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">&amp;</span> <span class="n">e</span><span class="p">);</span>
<span class="k">const</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">get_shape</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">done</span><span class="p">();</span>
</pre>
   <p>Building on earlier examples, this might be implemented more fully as: <a href="https://godbolt.org/g/PPTtrW">https://godbolt.org/g/PPTtrW</a>.
We need <code class="highlight"><span class="n">get_shape</span></code> to know what iteration domain to call <code class="highlight"><span class="n">set_value</span></code> over, and <code class="highlight"><span class="n">done</span></code> because in a parallel use case the continuation itself cannot know when
it is complete.</p>
   <p>There would be some cost here in deciding repeatedly to skip the exception.</p>
   <p>Another option is to say that set_exception only be callable once:</p>
<pre class="highlight"><span class="kt">void</span> <span class="nf">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">idx</span><span class="p">,</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">value</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">);</span>
<span class="k">const</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">get_shape</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">done</span><span class="p">();</span>
</pre>
   <p>In this design the implementation can pass an exception through more
directly as in <a href="https://godbolt.org/g/gLN72t">https://godbolt.org/g/gLN72t</a>.</p>
   <p>We might also separate iteration from initialization, and allow the promise to
consume its inputs immediately, executing trivially under certain circumstances,
for example passing the exception through without practical iteration as above:</p>
<pre class="highlight"><span class="kt">void</span> <span class="nf">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">);</span>
<span class="k">const</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">get_shape</span><span class="p">()</span> <span class="k">const</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">execute_at</span><span class="p">(</span><span class="kt">int</span> <span class="n">idx</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">done</span><span class="p">();</span>
</pre>
   <p>This design could be utilized as in <a href="https://godbolt.org/g/RmhaFb">https://godbolt.org/g/RmhaFb</a>.</p>
   <p>Finally, in rethinking bulk in this way we should consider what the result and
shared factory functions (<code class="highlight"><span class="n">RF</span></code> and <code class="highlight"><span class="n">SF</span></code> types in the above) mean, in two
specific areas:</p>
   <ul>
    <li data-md="">
     <p>Should the factory functions be independent of the data stream, or should
 they be part of the data processing operation?</p>
    <li data-md="">
     <p>Should the continuation explicitly translate the result variable into an
 output?</p>
   </ul>
   <p>For the first, we might consider changing the factory function API to be
parameterized by the value and the shape. This falls cleanly out of the
separated <code class="highlight"><span class="n">executor_at</span></code> design above, such that the factory functions run when <code class="highlight"><span class="n">set_value</span></code> and <code class="highlight"><span class="n">set_exception</span></code> are called. For example, if we take a vector as
input, it would make a lot of sense to be able to generate an output that
matches the input vector size, based on a size that was computed in the
processing stream. If we pass a reference to the input value into the result
factory, we can return a vector of that size directly as the result to write to.</p>
   <p>The shape can also be considered in this way, and be computed from the input.
For example, if we have an exception, return a shape of 1 and we immediately
tell the executor that we want to handle the exception as a single stream.
If we do not do this we will always execute the full iteration domain, even if
all but one instance is going to return directly.</p>
   <p>On the second point, output processing at the moment is slightly difficult in
that while we can manually perform a reduction operation such that the result
variable is a reduced value or exception, we have no function that runs at the
end of processing that unpacks this again. Clearly with the above task proposal
we can do this as part of the <code class="highlight"><span class="n">done</span><span class="p">()</span></code> call - so exposing a means to modify that
operation is a powerful primitive.</p>
   <p>A very limited implementation of parameterising the result factory can be seen
in <a href="https://godbolt.org/g/jDVhPC">https://godbolt.org/g/jDVhPC</a>.</p>
   <p>In practice, if we produce a general bulk task, we do not have to constrain the
factory functions in any way - they are all properties of the task and called
when the executor performs certain operations. We should only specify a few
standard ones that implement reasonable basic semantics.</p>
   <p>This is a more flexible and powerful model, and we believe one that is equally
easy to understand. There may be concerns about implementation cost.
For example, running work in <code class="highlight"><span class="n">done</span><span class="p">()</span></code> may be a costly additional operation that
needs pre-synchronization to work, after the primary bulk operation completes.
In practice, though, given that we have to return the object anyway, and that
object might have an arbitrary move constructor, we believe any such concerns
would need strong justification.</p>
   <h2 class="heading settled" data-level="7" id="wording"><span class="secno">7. </span><span class="content">Proposed New Wording for P0443</span><a class="self-link" href="#wording"></a></h2>
   <h3 class="heading settled" data-level="7.1" id="promiserequire"><span class="secno">7.1. </span><span class="content"><code class="highlight"><span class="n">Promise</span></code> requirements</span><a class="self-link" href="#promiserequire"></a></h3>
   <p>A type <code class="highlight"><span class="n">P</span></code> meets the <code class="highlight"><span class="n">Promise</span></code> requirements for some value type <code class="highlight"><span class="n">T</span></code> if an
instance <code class="highlight"><span class="n">p</span></code> of <code class="highlight"><span class="n">P</span></code> satisfies the requirements in the table below.</p>
   <table>
    <tbody>
     <tr>
      <th>Expression
      <th>Return Type
      <th>Operational semantics
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;&amp;</span><span class="p">)</span></code>
      <td>void
      <td> Defined if T is not void. Completes the promise with a value.
      Should accept by forwarding reference. 
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">()</span></code>
      <td>void
      <td>Defined if T is void. Completes the promise with no value.
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="p">)</span></code>
      <td>void
      <td> Completes the promise with an exception wrapped in a <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span></code>. 
   </table>
   <h3 class="heading settled" data-level="7.2" id="onewayrequire"><span class="secno">7.2. </span><span class="content">OneWayFutureContinuation requirements</span><a class="self-link" href="#onewayrequire"></a></h3>
    A type <code class="highlight"><span class="n">OFC</span></code> meets the OneWayFutureContinuation requirements if <code class="highlight"><span class="n">OFC</span></code> satisfies
the requirements of <code class="highlight"><span class="n">MoveConstructible</span></code> and for an instance <code class="highlight"><span class="n">ofc</span></code> of <code class="highlight"><span class="n">OFC</span></code>, <code class="highlight"><span class="n">INVOKE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OFC</span><span class="o">></span><span class="p">(</span><span class="n">ofc</span><span class="p">))</span></code> is valid. 
   <h3 class="heading settled" data-level="7.3" id="twowayrequire"><span class="secno">7.3. </span><span class="content">TwoWayFutureContinuation requirements</span><a class="self-link" href="#twowayrequire"></a></h3>
    A type <code class="highlight"><span class="n">TFC</span></code> meets the <code class="highlight"><span class="n">TwoWayFutureContinuation</span></code> requirements if <code class="highlight"><span class="n">TFC</span></code> satisfies the requirements of <code class="highlight"><span class="n">MoveConstructible</span></code> and for an instance <code class="highlight"><span class="n">tfc</span></code> of <code class="highlight"><span class="n">TFC</span></code> and  a value <code class="highlight"><span class="n">p</span></code> whose type, <code class="highlight"><span class="n">P</span></code> satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements and
for which <code class="highlight"><span class="n">INVOKE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">P</span><span class="o">></span><span class="p">(</span><span class="n">p</span><span class="p">))</span></code> is valid. 
   <h3 class="heading settled" data-level="7.4" id="thenrequire"><span class="secno">7.4. </span><span class="content">ThenFutureContinuation requirements</span><a class="self-link" href="#thenrequire"></a></h3>
    A type <code class="highlight"><span class="n">THFC</span></code> meets the <code class="highlight"><span class="n">TwoWayFutureContinuation</span></code> requirements if <code class="highlight"><span class="n">THFC</span></code> satisfies the requirements of <code class="highlight"><span class="n">MoveConstructible</span></code>, and for an
instance <code class="highlight"><span class="n">thfc</span></code> of <code class="highlight"><span class="n">TFC</span></code> and a value <code class="highlight"><span class="n">p</span></code> whose type, <code class="highlight"><span class="n">P</span></code> that satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements and where <code class="highlight"><span class="n">INVOKE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">P</span><span class="o">></span><span class="p">(</span><span class="n">p</span><span class="p">))</span></code> is valid and
returns a value <code class="highlight"><span class="n">pout</span></code> of type <code class="highlight"><span class="n">POUT</span></code> that satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements
for some value type <code class="highlight"><span class="n">TIn</span></code>, potentially <code class="highlight"><span class="kt">void</span></code>, that is known to the caller. 
   <h3 class="heading settled" data-level="7.5" id="onewaychanges"><span class="secno">7.5. </span><span class="content">Changes to OneWayExecutor requirements</span><a class="self-link" href="#onewaychanges"></a></h3>
    In the Table below, <code class="highlight"><span class="n">x</span></code> denotes a (possibly const) executor object of type <code class="highlight"><span class="n">X</span></code> and <code class="highlight"><span class="n">f</span></code> denotes an object of type <code class="highlight"><span class="n">F</span><span class="o">&amp;&amp;</span></code> that satisfies the requirements
of <code class="highlight"><span class="n">OneWayFutureContinuation</span></code>. 
   <h3 class="heading settled" data-level="7.6" id="twowaychanges"><span class="secno">7.6. </span><span class="content">Changes to TwoWayExecutor requirements</span><a class="self-link" href="#twowaychanges"></a></h3>
    In the Table below, <code class="highlight"><span class="n">x</span></code> denotes a (possibly const) executor object of type <code class="highlight"><span class="n">X</span></code>, <code class="highlight"><span class="n">f</span></code> denotes a an object of type <code class="highlight"><span class="n">F</span><span class="o">&amp;&amp;</span></code> that satisfies the requirements of <code class="highlight"><span class="n">TwoWayFutureContinuation</span></code> and <code class="highlight"><span class="n">R</span></code> is <code class="highlight"><span class="kt">void</span></code> or denotes the value type of a
value <code class="highlight"><span class="n">p</span></code> of type <code class="highlight"><span class="n">P</span><span class="o">&amp;&amp;</span></code> that satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements for value type <code class="highlight"><span class="n">R</span></code> and that may be passed to the expression <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">p</span><span class="p">))</span></code>. 
   <table>
    <tbody>
     <tr>
      <th>Expression
      <th>Return Type
      <th>Operational semantics
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">twoway_execute</span><span class="p">(</span><span class="n">f</span><span class="p">)</span></code>
      <td> A type that satisfies the Future requirements for the value type <code class="highlight"><span class="n">R</span></code>. 
      <td>
        Creates an execution agent which invokes <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">p</span><span class="p">)</span></code> for some value <code class="highlight"><span class="n">p</span></code> of type <code class="highlight"><span class="n">P</span></code> that
      satisfies the requirements of <code class="highlight"><span class="n">Promise</span></code> for value type <code class="highlight"><span class="n">R</span></code>, with the call
      to <code class="highlight"><span class="n">DECAY_COPY</span></code> being evaluated in the thread that called <code class="highlight"><span class="n">twoway_execute</span></code>. 
       <p>
        May block pending completion of DECAY_COPY( std::forward
        <f>(f))(p).</f>
       </p>
       <p>The invocation of twoway_execute synchronizes with
      (C++Std [intro.multithread]) the invocation of f.</p>
       <p>Stores the result of a call to <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">r</span><span class="p">)</span></code>, <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">()</span></code>, or <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">e</span><span class="p">)</span></code> for <code class="highlight"><span class="n">r</span></code> of type <code class="highlight"><span class="n">R</span></code> or <code class="highlight"><span class="n">e</span></code> of type <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span></code> in the associated shared state of the resulting <code class="highlight"><span class="n">Future</span></code>.</p>
   </table>
   <h3 class="heading settled" data-level="7.7" id="thenchanges"><span class="secno">7.7. </span><span class="content">Changes to ThenExecutor requirements</span><a class="self-link" href="#thenchanges"></a></h3>
    In the Table below, <code class="highlight"><span class="n">x</span></code> denotes a (possibly const) executor object of type <code class="highlight"><span class="n">X</span></code>, <code class="highlight"><span class="n">fut</span></code> denotes a future object satisfying the <code class="highlight"><span class="n">Future</span></code> requirements, <code class="highlight"><span class="n">f</span></code> denotes
a function object of type <code class="highlight"><span class="n">F</span><span class="o">&amp;&amp;</span></code> that satisfies the requirements of <code class="highlight"><span class="n">ThenFutureContinuation</span></code> and <code class="highlight"><span class="n">R</span></code> is <code class="highlight"><span class="kt">void</span></code> or denotes the value type of a value <code class="highlight"><span class="n">p</span></code> of type <code class="highlight"><span class="n">P</span><span class="o">&amp;&amp;</span></code> that satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements for value type <code class="highlight"><span class="n">R</span></code> and that may be passed to the expression <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">p</span><span class="p">))</span></code>. 
   <table>
    <tbody>
     <tr>
      <th>Expression
      <th>Return Type
      <th>Operational semantics
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">then_execute</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">fut</span><span class="p">)</span></code>
      <td> A type that satisfies the Future requirements for the value type <code class="highlight"><span class="n">R</span></code>. 
      <td>
        When <code class="highlight"><span class="n">fut</span></code> is ready, creates an execution agent which invokes <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">p</span><span class="p">)</span></code> for some value <code class="highlight"><span class="n">p</span></code> of type <code class="highlight"><span class="n">P</span></code> that
      satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements for value type <code class="highlight"><span class="n">R</span></code>, with the call to <code class="highlight"><span class="n">DECAY_COPY</span></code> being evaluated in the thread that called then_execute. 
       <p>May block pending completion of <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">p</span><span class="p">)</span></code>.</p>
       <p>The invocation of <code class="highlight"><span class="n">then_execute</span></code> synchronizes with (C++Std
      [intro.multithread]) the invocation of <code class="highlight"><span class="n">f</span></code>.</p>
       <p>If <code class="highlight"><span class="n">fut</span></code> is ready with a value, calls <code class="highlight"><span class="n">f</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">r</span><span class="p">)</span></code>, if <code class="highlight"><span class="n">fut</span></code> is ready
      and the value is void calls <code class="highlight"><span class="n">f</span><span class="p">.</span><span class="n">set_value</span><span class="p">()</span></code>. If <code class="highlight"><span class="n">fut</span></code> is ready with an
      exception calls <code class="highlight"><span class="n">f</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">e</span><span class="p">)</span></code>.</p>
       <p>Stores the result of a call to <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">r</span><span class="p">)</span></code>, <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">()</span></code>, or <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">e</span><span class="p">)</span></code> for <code class="highlight"><span class="n">r</span></code> of type <code class="highlight"><span class="n">R</span></code> or <code class="highlight"><span class="n">e</span></code> of type <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span></code> in the associated shared state of the resulting <code class="highlight"><span class="n">Future</span></code>.</p>
   </table>
   <h3 class="heading settled" data-level="7.8" id="bulkchanges"><span class="secno">7.8. </span><span class="content">Changes to Bulk requirements in general</span><a class="self-link" href="#bulkchanges"></a></h3>
    Separate all bulk-related operations into a separate document targeted at a TS. 
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

  var sidebarMedia = window.matchMedia('screen and (min-width: 78em)');
  var autoToggle   = function(e){ toggleSidebar(e.matches) };
  if(sidebarMedia.addListener) {
    sidebarMedia.addListener(autoToggle);
  }

  function toggleSidebar(on) {
    if (on == undefined) {
      on = !document.body.classList.contains('toc-sidebar');
    }

    /* Don’t scroll to compensate for the ToC if we’re above it already. */
    var headY = 0;
    var head = document.querySelector('.head');
    if (head) {
      // terrible approx of "top of ToC"
      headY += head.offsetTop + head.offsetHeight;
    }
    var skipScroll = window.scrollY < headY;

    var toggle = document.getElementById('toc-toggle');
    var tocNav = document.getElementById('toc');
    if (on) {
      var tocHeight = tocNav.offsetHeight;
      document.body.classList.add('toc-sidebar');
      document.body.classList.remove('toc-inline');
      toggle.innerHTML = collapseSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, 0 - tocHeight);
      }
      tocNav.focus();
      sidebarMedia.addListener(autoToggle); // auto-collapse when out of room
    }
    else {
      document.body.classList.add('toc-inline');
      document.body.classList.remove('toc-sidebar');
      toggle.innerHTML = expandSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, tocNav.offsetHeight);
      }
      if (toggle.matches(':hover')) {
        /* Unfocus button when not using keyboard navigation,
           because I don’t know where else to send the focus. */
        toggle.blur();
      }
    }
  }

  function createSidebarToggle() {
    /* Create the sidebar toggle in JS; it shouldn’t exist when JS is off. */
    var toggle = document.createElement('a');
      /* This should probably be a button, but appearance isn’t standards-track.*/
    toggle.id = 'toc-toggle';
    toggle.class = 'toc-toggle';
    toggle.href = '#toc';
    toggle.innerHTML = collapseSidebarText;

    sidebarMedia.addListener(autoToggle);
    var toggler = function(e) {
      e.preventDefault();
      sidebarMedia.removeListener(autoToggle); // persist explicit off states
      toggleSidebar();
      return false;
    }
    toggle.addEventListener('click', toggler, false);


    /* Get <nav id=toc-nav>, or make it if we don’t have one. */
    var tocNav = document.getElementById('toc-nav');
    if (!tocNav) {
      tocNav = document.createElement('p');
      tocNav.id = 'toc-nav';
      /* Prepend for better keyboard navigation */
      document.body.insertBefore(tocNav, document.body.firstChild);
    }
    /* While we’re at it, make sure we have a Jump to Toc link. */
    var tocJump = document.getElementById('toc-jump');
    if (!tocJump) {
      tocJump = document.createElement('a');
      tocJump.id = 'toc-jump';
      tocJump.href = '#toc';
      tocJump.innerHTML = tocJumpText;
      tocNav.appendChild(tocJump);
    }

    tocNav.appendChild(toggle);
  }

  var toc = document.getElementById('toc');
  if (toc) {
    createSidebarToggle();
    toggleSidebar(sidebarMedia.matches);

    /* If the sidebar has been manually opened and is currently overlaying the text
       (window too small for the MQ to add the margin to body),
       then auto-close the sidebar once you click on something in there. */
    toc.addEventListener('click', function(e) {
      if(e.target.tagName.toLowerCase() == "a" && document.body.classList.contains('toc-sidebar') && !sidebarMedia.matches) {
        toggleSidebar(false);
      }
    }, false);
  }
  else {
    console.warn("Can’t find Table of Contents. Please use <nav id='toc'> around the ToC.");
  }

  /* Wrap tables in case they overflow */
  var tables = document.querySelectorAll(':not(.overlarge) > table.data, :not(.overlarge) > table.index');
  var numTables = tables.length;
  for (var i = 0; i < numTables; i++) {
    var table = tables[i];
    var wrapper = document.createElement('div');
    wrapper.className = 'overlarge';
    table.parentNode.insertBefore(wrapper, table);
    wrapper.appendChild(table);
  }

})();
</script>