Input and output
Coroutines can accept()
inputs and yield(...)
outputs. To ensure type safety, the types for inputs and outputs must be declared as part of the co
macro call (see declaration).
Input
Within coroutine code, accept()
can be used to accept input of the declared type. The call suspends the coroutine until the value is available.
Example: accept()
usage
var greeter = pecan.Co.co({
trace('Hello, ${accept()}, from ${accept()}!');
}, (_ : String)).run();
greeter.give("Haxe");
greeter.give("pecan"); // output: Hello, Haxe, from pecan!
All accept()
calls within an expression are evaluated before the expression itself. The evaluation order of complex expressions involving calls to accept()
and other functions may therefore be different than expected. Boolean operators with accept()
will not short-circuit.
Output
Within coroutine code, yield(...)
can be used to provide output from the coroutine. The call suspends the coroutine until the value is taken.
Example: yield(...)
usage
var languages = pecan.Co.co({
yield("Haxe");
yield("Haxe 4");
}, null, (_ : String)).run();
trace('${languages.take()} is awesome!'); // output: Haxe is awesome!
trace('${languages.take()} is awesome!'); // output: Haxe 4 is awesome!
Custom input functions
It is possible to declare methods similar to accept
. These methods must:
- have the
:pecan.accept
metadata; - take the coroutine
pecan.ICo<...>
as their last argument, ideally optional; - take a function
T->Void
as their second-to-last argument, ideally optional; and - have a return type of the same type
T
.
Functions declared this way can then be called from within coroutines, with the last two arguments filled in automatically. The second-to-last argument is how the custom input function provides the "real" return value.
The return value of the function is never used! It is only used for type inference. Returning
null
(or a default value on static targets) is recommended.
Unlike custom suspending functions, custom input functions always suspend the coroutine and always wake it up when the value is returned.
Example: delay that eventually returns a String
class Foobar {
@:pecan.accept public static function acceptDelay(
ms:Int,
?ret:String->Void,
?co:pecan.ICo<Any, Any, Any>
):String {
haxe.Timer.delay(() -> ret("foo"), ms);
return null;
}
}
Usage:
pecan.Co.co({
trace("Hello,");
var x = Foobar.acceptDelay(1000);
trace(x); // output: foo
}).run();