Description
The primitives provided in task
and comm
are very primitive. Too primitive to write a tutorial chapter about without sounding completely lame. So I tried to write a helper function which helps create a channel back from a child task to its parent. None of the existing tests or examples seem to do this. And, apparently, with good reason.
Below is what I have. It doesn't work. Writing new task-creation utilities will typically require type parameters. We currently can not spawn functions with type parameters, so the 'landing pad' helper that such a utility would spawn can not be generic.
I half got around this with a clunky reinterpret_cast
, but the resulting program doesn't work when the To
type has a different size than an int
, because the port being created in helper
doesn't know its type.
Not being able to write generic utility functions around task spawning seems unacceptable. I'm marking this as a blocker because I don't think we can release a language that is supposed to have tasks as one of its interesting features with such a primitive set of task operations. I'm holding off on writing the tutorial section about tasks until we figure out a solution here. (Or maybe it already exists and I just didn't see it.)
use std;
import std::{task, comm};
type connected_fn<To, From> = fn(comm::port<To>, comm::chan<From>);
fn spawn_connected<uniq To, uniq From>(f: connected_fn<To, From>)
-> {task: task::task, in: comm::port<From>, out: comm::chan<To>} unsafe {
fn helper(d: (comm::chan<int>,
comm::chan<comm::chan<int>>,
connected_fn<int, int>)) {
let (out, send_in, f) = d;
let in = comm::port::<int>();
comm::send(send_in, comm::chan(in));
f(in, out);
}
let in = comm::port::<From>();
let get_out = comm::port::<comm::chan<To>>();
let task = task::spawn((comm::chan(in), comm::chan(get_out), f),
std::unsafe::reinterpret_cast(helper));
ret {task: task, in: in, out: comm::recv(get_out)};
}
tag msg { msg(int); quit; }
fn worker(in: comm::port<msg>, out: comm::chan<int>) {
while true {
alt comm::recv(in) {
msg(i) { comm::send(out, i * 10); }
quit. { break; }
}
}
}
fn main() {
let {task, in, out} = spawn_connected(worker);
comm::send(out, msg(20));
log_err comm::recv(in);
comm::send(out, quit);
}