Thread overview
Delegate returning itself
Dec 06, 2014
Jonathan Marler
Dec 06, 2014
Adam D. Ruppe
Dec 08, 2014
Jonathan Marler
Dec 08, 2014
Jonathan Marler
Dec 08, 2014
Marc Schütz
Dec 08, 2014
Jonathan Marler
Dec 08, 2014
Ali Çehreli
December 06, 2014
Is there a way to create a delegate that returns itself?

alias MyDelegate delegate() MyDelegate;
// OR
alias MyDelegate = MyDelegate delegate();

When I compile this I get:

Error: alias MyDelegate recursive alias declaration

The error makes sense but I still feel like there should be a way to create a delegate that returns itself.  Maybe there's something I haven't thought of.  Does anyone have an idea on how to do this?
December 06, 2014
The problem is the recursive *alias* rather than the delegate. Just don't use the alias name inside itself so like

alias MyDelegate = void delegate() delegate();

will work. The first void delegate() is the return value of the MyDelegate type.
December 08, 2014
On Saturday, 6 December 2014 at 15:46:16 UTC, Adam D. Ruppe wrote:
> The problem is the recursive *alias* rather than the delegate. Just don't use the alias name inside itself so like
>
> alias MyDelegate = void delegate() delegate();
>
> will work. The first void delegate() is the return value of the MyDelegate type.

Yes I tried that as well.  It still doesn't solve the issue.  The delegate being returned doesn't return a delegate, it returns the "void" type.  You would need to write delegate() delegate() delegate() delegate() ...FOREVER.  I can't figure out a way to write this in the language even though the machine code it generates should be quite trivial.
December 08, 2014
On Monday, 8 December 2014 at 14:08:33 UTC, Jonathan Marler wrote:
> On Saturday, 6 December 2014 at 15:46:16 UTC, Adam D. Ruppe wrote:
>> The problem is the recursive *alias* rather than the delegate. Just don't use the alias name inside itself so like
>>
>> alias MyDelegate = void delegate() delegate();
>>
>> will work. The first void delegate() is the return value of the MyDelegate type.
>
> Yes I tried that as well.  It still doesn't solve the issue.  The delegate being returned doesn't return a delegate, it returns the "void" type.  You would need to write delegate() delegate() delegate() delegate() ...FOREVER.  I can't figure out a way to write this in the language even though the machine code it generates should be quite trivial.

I did some digging and realized that C/C++ have the same problem.  I found a nice post on it with 2 potential solutions (http://c-faq.com/decl/recurfuncp.html).  I liked the second solution so I wrote up an example in D.  If anyone has any other ideas or can think of a way to improve my example feel free to post and let me know, thanks.import std.stdio;

struct StateFunc
{
  StateFunc function() func;
}
StateFunc state1()
{
  writeln("state1");
  return StateFunc(&state2);
}
StateFunc state2()
{
  writeln("state2");
  return StateFunc(&state3);
}
StateFunc state3()
{
  writeln("state3");
  return StateFunc(null);
}
void main(string[] args)
{
  StateFunc state = StateFunc(&state1);

  while(state.func != null) {
    state = state.func();
  }
}
December 08, 2014
On Monday, 8 December 2014 at 14:31:53 UTC, Jonathan Marler wrote:
> On Monday, 8 December 2014 at 14:08:33 UTC, Jonathan Marler wrote:
>> On Saturday, 6 December 2014 at 15:46:16 UTC, Adam D. Ruppe wrote:
>>> The problem is the recursive *alias* rather than the delegate. Just don't use the alias name inside itself so like
>>>
>>> alias MyDelegate = void delegate() delegate();
>>>
>>> will work. The first void delegate() is the return value of the MyDelegate type.
>>
>> Yes I tried that as well.  It still doesn't solve the issue.  The delegate being returned doesn't return a delegate, it returns the "void" type.  You would need to write delegate() delegate() delegate() delegate() ...FOREVER.  I can't figure out a way to write this in the language even though the machine code it generates should be quite trivial.
>
> I did some digging and realized that C/C++ have the same problem.
>  I found a nice post on it with 2 potential solutions (http://c-faq.com/decl/recurfuncp.html).  I liked the second solution so I wrote up an example in D.  If anyone has any other ideas or can think of a way to improve my example feel free to post and let me know, thanks.import std.stdio;
>
> struct StateFunc
> {
>   StateFunc function() func;
> }
> StateFunc state1()
> {
>   writeln("state1");
>   return StateFunc(&state2);
> }
> StateFunc state2()
> {
>   writeln("state2");
>   return StateFunc(&state3);
> }
> StateFunc state3()
> {
>   writeln("state3");
>   return StateFunc(null);
> }
> void main(string[] args)
> {
>   StateFunc state = StateFunc(&state1);
>
>   while(state.func != null) {
>     state = state.func();
>   }
> }

Nice! Using alias this, you can call the struct directly:

struct StateFunc
{
  StateFunc function() func;
  alias func this;
}
state = state();

Now there still needs to be a way to just `return &state2;` instead of `return StateFunc(&state2);`...
December 08, 2014
On Monday, 8 December 2014 at 14:38:37 UTC, Marc Schütz wrote:
> On Monday, 8 December 2014 at 14:31:53 UTC, Jonathan Marler wrote:
>> On Monday, 8 December 2014 at 14:08:33 UTC, Jonathan Marler wrote:
>>> On Saturday, 6 December 2014 at 15:46:16 UTC, Adam D. Ruppe wrote:
>>>> The problem is the recursive *alias* rather than the delegate. Just don't use the alias name inside itself so like
>>>>
>>>> alias MyDelegate = void delegate() delegate();
>>>>
>>>> will work. The first void delegate() is the return value of the MyDelegate type.
>>>
>>> Yes I tried that as well.  It still doesn't solve the issue.  The delegate being returned doesn't return a delegate, it returns the "void" type.  You would need to write delegate() delegate() delegate() delegate() ...FOREVER.  I can't figure out a way to write this in the language even though the machine code it generates should be quite trivial.
>>
>> I did some digging and realized that C/C++ have the same problem.
>> I found a nice post on it with 2 potential solutions (http://c-faq.com/decl/recurfuncp.html).  I liked the second solution so I wrote up an example in D.  If anyone has any other ideas or can think of a way to improve my example feel free to post and let me know, thanks.import std.stdio;
>>
>> struct StateFunc
>> {
>>  StateFunc function() func;
>> }
>> StateFunc state1()
>> {
>>  writeln("state1");
>>  return StateFunc(&state2);
>> }
>> StateFunc state2()
>> {
>>  writeln("state2");
>>  return StateFunc(&state3);
>> }
>> StateFunc state3()
>> {
>>  writeln("state3");
>>  return StateFunc(null);
>> }
>> void main(string[] args)
>> {
>>  StateFunc state = StateFunc(&state1);
>>
>>  while(state.func != null) {
>>    state = state.func();
>>  }
>> }
>
> Nice! Using alias this, you can call the struct directly:
>
> struct StateFunc
> {
>   StateFunc function() func;
>   alias func this;
> }
> state = state();
>
> Now there still needs to be a way to just `return &state2;` instead of `return StateFunc(&state2);`...

Nice addition! I can't think of a way to solve the implicit conversion from function pointer to struct, but not a big deal.  I'm mostly glad I found a way to do this with no overhead and no awkward casting.  Adding the implicit conversion would be icing on the cake.
December 08, 2014
On 12/06/2014 07:28 AM, Jonathan Marler wrote:
> Is there a way to create a delegate that returns itself?

Y combinator helps exactly with that:

  http://rosettacode.org/wiki/Y_combinator#D

Copying the code from there:

import std.stdio, std.traits, std.algorithm, std.range;

auto Y(S, T...)(S delegate(T) delegate(S delegate(T)) f) {
    static struct F {
        S delegate(T) delegate(F) f;
        alias f this;
    }
    return (x => x(x))(F(x => f((T v) => x(x)(v))));
}

void main() { // Demo code:
    auto factorial = Y((int delegate(int) self) =>
        (int n) => 0 == n ? 1 : n * self(n - 1)
    );

    auto ackermann = Y((ulong delegate(ulong, ulong) self) =>
        (ulong m, ulong n) {
            if (m == 0) return n + 1;
            if (n == 0) return self(m - 1, 1);
            return self(m - 1, self(m, n - 1));
    });

    writeln("factorial: ", 10.iota.map!factorial);
    writeln("ackermann(3, 5): ", ackermann(3, 5));
}

Ali