www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - inner functions calling each other - how to do this with inner struct?

reply Ivan Kazmenko <gassa mail.ru> writes:
Hi,

1. What works.

Inside a function (outerFun), I've got inner functions fun1 and 
fun2 which have to recursively call each other.  Just writing 
them one after the other does not work.  I've managed to find a 
trick to make it work though, which is to add empty compile-time 
parameters to fun1 and fun2:

-----
import std.stdio;

void outerFun () {
     void fun1 () (int x) {
         writeln (x);
         if (x > 0) fun2 (x - 1);
     }

     void fun2 () (int y) {
         writeln (y);
         if (y > 1) fun1 (y - 2);
     }

     fun2 (10);
}

void main () {outerFun ();}
-----



2. What doesn't work.

Next, I'd like to have an inner function fun1 and an inner struct 
S with a method fun2, and an instance s of struct S.  I want to 
be able to call s.fun2 from fun1 and fun1 back from s.fun2.  Now, 
I can't figure out how to do that.  The same trick does not seem 
to work:

-----
import std.stdio;

void outerFun () {
     struct S () {
         void fun2 (int x) {
             writeln (x);
             if (x > 0) fun1 !() (x - 1);
         }
     }

     S !() s;

     void fun1 () (int y) {
         writeln (y);
         if (y > 1) s.fun2 (y - 2);
     }

     fun1 (10);
}

void main () {outerFun ();}
-----

Here are the errors I get:
-----
test2.d(7): Error: template instance fun1!() template 'fun1' is 
not defined, did
you mean fun2?
test2.d(11): Error: template instance test2.outerFun.S!() error 
instantiating
-----

So, is this mutual recursion (inner function and method of a 
fixed instance of an inner struct) possible?  This does not seem 
theoretically wrong: we have to maintain exactly one outer 
context pointer (to outerFun's current stack frame) for each 
recursive call.



3. What also doesn't work.

Here is another attempt, where the outer scope is a struct, not a 
function.  Again, I want to be able to call fun1 from s.fun2 and 
s.fun2 from fun1.

-----
import std.stdio;

struct outerStruct {
     struct S {
         void fun2 (int x) {
             writeln (x);
             if (x > 0) fun1 (x - 1);
         }
     }

     S s;

     void fun1 (int y) {
         writeln (y);
         if (y > 1) s.fun2 (y - 2);
     }
}

void main () {outerStruct os; os.fun1 (10);}
-----

With no compile-time parameters, this just says:
-----
test3.d(7): Error: this for fun1 needs to be type outerStruct not 
type S
-----

Apparently, the call to fun1 is not able to get the context 
pointer to outerStruct os and use it to call fun1.  Again, I 
don't see a theoretical limitation here.  Did I fail to express 
my intent to the compiler, or is what I want impossible with the 
current implementation?



4. Module scope.

At module scope (no outer context pointer needed), everything 
works fine without the need for tricks:

-----
import std.stdio;

struct S {
     void fun2 (int x) {
         writeln (x);
         if (x > 0) fun1 (x - 1);
     }
}

S s;

void fun1 (int y) {
     writeln (y);
     if (y > 1) s.fun2 (y - 2);
}

void main () {fun1 (10);}
-----

Ivan Kazmenko.
Feb 03 2016
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 3 February 2016 at 14:01:24 UTC, Ivan Kazmenko 
wrote:
 1. What works.
Read my post here: http://stackoverflow.com/questions/34398408/struct-declaration-order/34398642#34398642 then see if you can use the same reasoning on your problem.
Feb 03 2016
parent Ivan Kazmenko <gassa mail.ru> writes:
On Wednesday, 3 February 2016 at 15:09:35 UTC, Adam D. Ruppe 
wrote:
 Read my post here:

 http://stackoverflow.com/questions/34398408/struct-declaration-order/34398642#34398642

 then see if you can use the same reasoning on your problem.
This indeed works without any other tricks such as compile-time parameters: ----- import std.stdio; void outerFun () { struct Holder { static struct S { void fun2 (int x) { writeln (x); if (x > 0) fun1 (x - 1); } } static S s; static void fun1 (int y) { writeln (y); if (y > 1) s.fun2 (y - 2); } } Holder.fun1 (10); } void main () {outerFun ();} ----- Thank you! Ivan Kazmenko.
Feb 03 2016