<p dir="auto">The primitives provided in <code class="notranslate">task</code> and <code class="notranslate">comm</code> are <em>very</em> 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.</p>
<p dir="auto">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.</p>
<p dir="auto">I half got around this with a clunky <code class="notranslate">reinterpret_cast</code>, but the resulting program doesn't work when the <code class="notranslate">To</code> type has a different size than an <code class="notranslate">int</code>, because the port being created in <code class="notranslate">helper</code> doesn't know its type.</p>
<p dir="auto">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.)</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="use std;
import std::{task, comm};

type connected_fn&lt;To, From&gt; = fn(comm::port&lt;To&gt;, comm::chan&lt;From&gt;);
fn spawn_connected&lt;uniq To, uniq From&gt;(f: connected_fn&lt;To, From&gt;)
    -&gt; {task: task::task, in: comm::port&lt;From&gt;, out: comm::chan&lt;To&gt;} unsafe {
    fn helper(d: (comm::chan&lt;int&gt;,
                  comm::chan&lt;comm::chan&lt;int&gt;&gt;,
                  connected_fn&lt;int, int&gt;)) {
        let (out, send_in, f) = d;
        let in = comm::port::&lt;int&gt;();
        comm::send(send_in, comm::chan(in));
        f(in, out);
    }
    let in = comm::port::&lt;From&gt;();
    let get_out = comm::port::&lt;comm::chan&lt;To&gt;&gt;();
    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&lt;msg&gt;, out: comm::chan&lt;int&gt;) {
    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);
}"><pre class="notranslate"><code class="notranslate">use std;
import std::{task, comm};

type connected_fn&lt;To, From&gt; = fn(comm::port&lt;To&gt;, comm::chan&lt;From&gt;);
fn spawn_connected&lt;uniq To, uniq From&gt;(f: connected_fn&lt;To, From&gt;)
    -&gt; {task: task::task, in: comm::port&lt;From&gt;, out: comm::chan&lt;To&gt;} unsafe {
    fn helper(d: (comm::chan&lt;int&gt;,
                  comm::chan&lt;comm::chan&lt;int&gt;&gt;,
                  connected_fn&lt;int, int&gt;)) {
        let (out, send_in, f) = d;
        let in = comm::port::&lt;int&gt;();
        comm::send(send_in, comm::chan(in));
        f(in, out);
    }
    let in = comm::port::&lt;From&gt;();
    let get_out = comm::port::&lt;comm::chan&lt;To&gt;&gt;();
    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&lt;msg&gt;, out: comm::chan&lt;int&gt;) {
    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);
}
</code></pre></div>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="fn main() {
    fn# foo&lt;T&gt;() { }

    // This wants to build a closure over type int,
    // but there's no way to do that while still being a bare function
    let f: fn#() = foo::&lt;int&gt;;
}"><pre class="notranslate"><code class="notranslate">fn main() {
    fn# foo&lt;T&gt;() { }

    // This wants to build a closure over type int,
    // but there's no way to do that while still being a bare function
    let f: fn#() = foo::&lt;int&gt;;
}
</code></pre></div>
<p dir="auto">As a result we can't do bare-fn spawn for generic functions, which is pretty important:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="#[test]
fn spawn_polymorphic() {
    fn# foo&lt;~T&gt;(x: T) { log_err x; }

    task::spawn2(true, foo);
    task::spawn2(42, foo);
}"><pre class="notranslate"><code class="notranslate">#[test]
fn spawn_polymorphic() {
    fn# foo&lt;~T&gt;(x: T) { log_err x; }

    task::spawn2(true, foo);
    task::spawn2(42, foo);
}
</code></pre></div>