On 09/23/2014 03:28 PM, monarch_dodra wrote:
On Tuesday, 23 September 2014 at 22:09:11 UTC, Ali Çehreli wrote:
So near and yet so far... :)

Ali

You explain "how" you want to achieve your goal, but I'm not sure I
understand "what" the goal is. Perhaps if you explain that in more
detail, I'd have a better understanding of the problem.

I've never used core.thread.Fibre, so I don't know what "yield(42);"
would do, so apologies if the question is stupid.

Sorry. You are right. :) I almost deleted all of the specifics to avoid any concrete example as I think the question is still valid.

Very briefly, fibers provide faster concurrency by executing both the owner and the fiber on the same thread. They are D's coroutines, without the much-missed 'yield' keyword. There is some language (runtime?) support for fibers though as the 'yield()' and 'call()' calls do involve context switching behind the scenes (much faster than thread context switching).

I am not experienced with them either but from the examples on the core.thread documentation it looks like a fiber cannot yield a value in D; it must cause side-effects first, and then yield(), so that the owner can observe the side-effect.

Fibers give the convenience of iteration a.la. opCall(), and InputRange interface comes naturally. (Example below.)

I played with the idea of enabling the yield(42) syntax from the fiber code just because it does not involve side-effects and is more intuitive. There are blog posts, thread discussions, and enhancement reports about the same.

So, my goal was the above: The client would make a yield(42) call, the data would be saved in a local variable automatically (the type of which is the question at hand), and then the result would be provided on an InputRange interface.

Additionally, although I am not aware of other examples of it, again as an experiment, I tried to see whether injecting user code by a template mixin would make any sense. Since template mixins are expanded where they are mixed-in, then I thought perhaps I could deduce a type from inside that code. I failed, you will succeed. :o)

Here is a working example with the minor inconvenience of having to specify ResultT from the outside, which seems redundant. The goal is to remove the need for that parameter.

Note that I am aware of the inheritance-based kind of fibers and the following may not make sense at all. I was just experimenting.

import std.stdio;
import core.thread;
import std.algorithm;

/* This is what the user provides. We will mix this in. */
mixin template Foo()
{
    void run()
    {
        /* Note how naturally the elements are produced in imperative
         * style: */
        foreach (i; 0 .. 10) {
            yield(i);    /* The element type is obviously 'int'. */
        }
    }
}

/* This is an InputRange that exposes the yielded values as
 * elements. PROBLEM: Admittedly minor, ResultT seems redundant. */

class FiberRange(alias Func, ResultT)
{
    mixin Func!();     // User code mixed-in
    ResultT result;    // The front element
    Fiber fiber;       // The fiber that does the work

    /* Supports the more natural yield(42) syntax. */
    final void yield(T : ResultT)(T result)
    {
        this.result = result;
        Fiber.yield;
    }

public:

    this()
    {
        /* He fiber is started by the user's 'run' function. */
        this.fiber = new Fiber(&run);
        this.fiber.call();
    }

    /* Trivial InputRange interface: */

    final
    @property
    bool empty() const
    {
        return fiber.state == Fiber.State.TERM;
    }

    final
    @property
    ResultT front() const
    {
        return result;
    }

    final
    void popFront()
    {
        this.fiber.call;
    }
}

/* Convenience function: */
auto fiberRange(alias Func, ResultT)()
{
    return new FiberRange!(Func, ResultT);
}

void main()
{
    /* Works like a charm! :p */
    auto result = fiberRange!(Foo, int)
                  .filter!(a => a % 2);

    assert(result.equal([1, 3, 5, 7, 9]));
}

Can we get rid of the ResultT template parameter? Tricks with variadic templates, the with statement, etc. come to mind but I could not manage it.

Ali

Reply via email to