The academic language Effekt has so-called effects. They are a generalization of throw
, yield
and await
which allow an executed function to "stop" in the middle of its execution, and then optionally continue. This would be a great feature for Gunpowder.
-
throw<E>: E → never
- interrupts with any value – it will act as the error
- never resumes
- not consuming is equivalent to a
try{}
block
-
(suffix after function call)
?: T / throw<T> → T
- unwraps a value or re-throws an error
- equivalent to
yield*
foryield
-
yield<T>: T → void
- interrupts with any value – it will act as the "next" value in iterable
- user code can resume without any value
- doesn't need to be consumed
-
yield*<T>: void / yield<T> → void
- iterrupts with an iterable, re-yields all values
- user code wantint to resume will consume the re-yielded iterable first, only then it will resume the function which used
yield*
- equivalent to the
?
suffix forthrow
-
await: T / await → T
- interrupts with a promise, resumes with its result
- resumed by an asynchronous runtime
- must be consumed in order to ever finish execution
fn divide(a: i32, b: i32): Fraction / throw<DivisionByZero> {
if b == 0 {
throw DivisionByZero();
} else {
return a / b;
}
}
fn fibonacci(): yield<i32> {
let a: i32 = 1;
let b: i32 = 1;
loop {
yield a;
[a, b] = [b, a + b];
}
}
fn wikiFeaturedArticle(): string / await / throw<NetworkError> {
const url = "https://en.wikipedia.org/w/api.php?feed=featured";
const response = await fetch(url);
if not response.ok { throw NetworkError(response.status); }
return await response.text();
}