---
# System prepended metadata

title: Draft coroutine factory return type

---

# Draft coroutine factory return type

Pros/cons of varieties of `next()`.

```typescript
/**
 * A multi-step computation that may be 
 * scheduled for a step by calling the 
 * [Generator.next] method.
 * 
 * Block lambdas that extend [GeneratorFn] specify
 * factories for [Generator]s.
 * 
 * Terminology note:
 * Coroutines may be represented as Generators
 * where [Generator.next] starts or resumes
 * computation and the coroutine pauses itself
 * when done with the step.
 * We avoid the term "coroutine" because many
 * programmers associate it narrowly with
 * parallelism.
 */
interface Generator<PAUSE_T, BUBBLE extends Bubble> {
  /**
   * Starts/resumes the computation and runs until
   * it pauses or completes.
   *
   * If the computation was [done] prior to the
   * start of the call or it is done at the end,
   * returns [Null].
   * This is the case for a [GeneratorFn] that
   * [returns][snippet/builtin/return].
   *
   * If the computation pauses, returns the value
   * associated with the decision to pause.
   * For a [GeneratorFn], this is the value passed to
   * [snippet/builtin/pause].
   */
  public next(): PAUSE_T | Null | BUBBLE;
  /**
   * True if subsequent calls to [next] would do
   * no work and return [Null].
   */
  public done: Boolean;
  /**
   * Should be called once it is realized that 
   * [next] is not going to be called again to
   * release resources needed by [next].
   *
   * After `close()` exits, [done] will be true.
   */
  public close(): Void;
}
```


## Variant 1: Null means no result / not-resumable.

```typescript
  public next(): PAUSE_T | Null | BUBBLE;
```

Pros:

- Simple interface.  No object allocation.

Cons:

- Either *PAUSE_T* needs to exclude null or there's an ambiguity about what `.next() == null` means.  If the latter, code that uses it generically needs to check `.done` separately and know to do so.
- *null* means "no result," not "don't expect any result after this"

## Variant 2: Option type.  None means no result / not-resumable.

```typescript
  public next(): Optional<PAUSE_T> | BUBBLE;
```

Pros:

- Unambiguous
- Reuses std type that is a semantic match
- Idiom `when (g.next()) { ... }`

Cons:

- If a target language has a result type especially for generators, like JavaScript's `{ next, done }` record, the backend needs to adapt.
- May require more pause value boxing when PAUSE_T is a pass-by-copy/primitive by copy.

## Variant 3: Generator helper type.

```typescript
  public next(): GeneratorResult<PAUSE_T> | BUBBLE;
```


```typescript
sealed interface GeneratorResult<out PAUSE_T> {
  public done: Boolean;
}

class GeneratorDone extends GeneratorResult<Never> {
  public get done(): Boolean { true }
}

class NextResult<PAUSE_T> extends GeneratorResult<PAUSE_T> {
  public value: PAUSE_T;
  public get done(): Boolean { false }
}
```

Pros:

- Unambiguous
- Idiom `when (g.next()) { ... }`
- Compiles to nice code on most backends.

Cons:

- Duplicative of optionals in Temper code.

Meh:

- If a target language has an optional type but does not have native support for generators, we can still connect this type to optionals.


## Variant 4: Bubble if next() ends without pausing.

```typescript
  public next(): PAUSE_T | Bubble;
```

Pros:

- No need for BUBBLE type parameter
- Slightly easier translation of *Generator.next* on target languages whose native *Generator* type throws (see near bottom about Python's *StopIteration*) to indicate no-next value.

Cons:

- Mild ambiguity between next() failed and next() successfully concluded correctly that there are no more values.


## Example usage

We need to check `done` in some fashion before using a value returned from next. Here's an example:

```typescript
let myGenerator = makeAGenerator { () extends GeneratorFn;;
  pause(1);
  // Client needs to call `next()` before continuing.
  console.log("About to return");
};

let x = myGenerator.next();
if (!myGenerator.done) { // not done
  console.log(x); // -> 1
}
let y = myGenerator.next();
if (!myGenerator.done) { // done
  console.log(y);
}
```

That might enable loops of this form for null-returning:

```typescript
// Variant 1, null-returning
while (true) {
  let x = myGenerator.next() orelse do {
    console.log("I'm so sad.");
    myGenerator.close();
    bubble();
  };
  if (myGenerator.done) {
    break; // Guaranteed null `x` but meh.
  }
  process(x);
}
myGenerator.close();
```

Or for helper return type:

```typescript
// Variant 3, using match
while (true) {
  let next = myGenerator.next() orelse do {
    console.log("I'm so sad.");
    myGenerator.close();
    bubble();
  };
  match (next) {
    is NextResult -> process(next.value);
    else -> break;
  }
}
myGenerator.close();
```

Or for bubbling:

```typescript
// Variant 4, bubbling
while (true) {
  let x = myGenerator.next() orelse do {
    if (myGenerator.done) {
      // Don't know if I should be sad?
      break;
    }
    console.log("I'm so sad.");
    myGenerator.close();
    bubble();
  };
  process(x);
}
myGenerator.close();
```

## Connecting to backend types: exceptions when no-next.

Some target languages raise an exception from a generator when
there is no next value.
For example, Python does `raise StopIteration()`.

```python
>>> def f():
...   yield 1
...   yield 2
...   yield 3
...
>>> i = f()
>>> type(i)
<class 'generator'>
>>> i.__next__()
1
>>> i.__next__()
2
>>> i.__next__()
3
>>> i.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>
```

Java does have `NoSuchElementException` but that is usually only
thrown when a client fails to check `.hasNext()` properly.

How do we translate `myGenerator.next()` uses from Temper code using
a generator that might have come from backend code?


### Variant 1, 2, 3: trap exception

```python=
# Python support code
def temper_generator_next(generator):
    try:
        return generator.__next__()
    except StopIteration:
        # For variant 1
        return None # Temper null
        # Or for variant 2
        return EmptyOption
        # Or for variant 3
        return DoneResult

# Then we can translate `foo.next()` to
temper_generator_next(foo)
```

### Variant 4

Make sure we treat *StopIteration* as a bubble.