www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Nested functions should be exempt from sequential visibility rules

reply "Nick Sabalausky" <a a.a> writes:
Regarding this:

http://d.puremagic.com/issues/show_bug.cgi?id=790

I submit that nested functions should be exempt from the usual sequential 
visibility rules. (Therefore, mutually recursive nested functions would 
become possible.)

Or at the very *least*, this horrific C-like workaround should be possible:

void foo()
{
    void b();
    void a() {...};
    void b() {...};
}

...Flame away! ;)
Apr 02 2012
next sibling parent reply James Miller <james aatch.net> writes:
 Sorry, I didn't mean this to go into "D.announce". Reposting in the proper
 place... Can this one be deleted?

Off Topic: In Gmail, it applied both labels to the one email, which is cool :D. Otherwise I think that the C-like workaround should be ok, the issue is with closures, what values should be visible to the closures? -- James Miller
Apr 02 2012
parent "Nick Sabalausky" <a a.a> writes:
"James Miller" <james aatch.net> wrote in message 
news:mailman.1324.1333434077.4860.digitalmars-d puremagic.com...
 [...]the issue
 is with closures, what values should be visible to the closures?

Personally, I don't much care ATM. Either way has it's pros and cons: A. Same as right now: The nested function can only access variables defined before it. Only difference is that it can *also* access "sibling" nested functions that are defined before *or* after. The benefit is that there's minimal change to the current "sequential visibility". B. Let nested funcs access *any* "sibling" symbol whether defined before or after. Presumably, the nested func would not be *callable* until after all the sibling symbols it accesses have been declared. The downside is that, I suspect, this might be more work to implement. The benefits are that it provides more flexibility and is more consistent with module-level declarations. That latter benefit would be import for code like this: void main() { mixin(import("script.d")); } I guess I would lean more towards "B", but it is a bigger change and I realize bigger changes meet bigger resistance at this point. So I'd be content either way because what's *more* important here is we ditch the (seemingly) silly restriction of "no mutually recursive nested funcs". 'Course, another approach would be to just for the compiler to treat this: void foo() { /+ code 1 +/ void a() {...}; /+ code 2 +/ void b() {...}; /+ code 3 +/ } Like this: void foo() { void delegate() a; void delegate() b; /+ code 1 +/ a = () {...}; /+ code 2 +/ b = () {...}; /+ code 3 +/ // Except that, naturally, a and b cannot // be re-assigned by the programmer, // and foo itself cannot access a or b // before the "a = ...;" and "b = ...;" lines // respectively. } This maybe makes the most sense, because nested funcs and anon-funcs-assigned-to-a-variable *are* so very similar anyway. But then again, this comes with the downside of "void main() { mixin(import("script.d")); }" causing strange semantics inside 'script.d'...but I guess such strange semantics in 'script.d' would be the case even without any nested funcs involved. Actually, this might be equivalent to approach "A" above.
Apr 03 2012
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 03/04/2012 07:38, Nick Sabalausky a écrit :
 Regarding this:

 http://d.puremagic.com/issues/show_bug.cgi?id=790

 I submit that nested functions should be exempt from the usual sequential
 visibility rules. (Therefore, mutually recursive nested functions would
 become possible.)

 Or at the very *least*, this horrific C-like workaround should be possible:

 void foo()
 {
      void b();
      void a() {...};
      void b() {...};
 }

 ...Flame away! ;)

This is a +1 .
Apr 03 2012
prev sibling next sibling parent reply Don Clugston <dac nospam.com> writes:
On 03/04/12 07:38, Nick Sabalausky wrote:
 Regarding this:

 http://d.puremagic.com/issues/show_bug.cgi?id=790

 I submit that nested functions should be exempt from the usual sequential
 visibility rules. (Therefore, mutually recursive nested functions would
 become possible.)

 Or at the very *least*, this horrific C-like workaround should be possible:

 void foo()
 {
      void b();
      void a() {...};
      void b() {...};
 }

 ...Flame away! ;)

This is asking for a complicated special case. In global scope, order of declarations doesn't matter. In function scope, order of declarations always matters. If you have type inference of function returns, things can get nasty: void foo() { auto b() { return a(); } X x = whatever; auto a() { return x; } } Now b actually depends on the declaration of x. So it's not enough to say that only function declarations are immune to ordering rules. Furthermore, any declaration before x, which calls b(), is using x even though x hasn't been initialized (or even declared) yet. Suddenly all kinds of horrible situations become possible, which could never happen before. In general, allowing forward references inside a function is far, far more difficult than in global scope. There are very many more special cases. Allowing it in global scope is quite complicated enough. You can always use a delegate, if you want recursive nested functions.
Apr 03 2012
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Don Clugston" <dac nospam.com> wrote in message 
news:jlecab$9gh$1 digitalmars.com...
 If you have type inference of function returns, things can get nasty:

 void foo()
 {
      auto b() { return a(); }
      X x = whatever;
      auto a() { return x; }
 }
 Now b actually depends on the declaration of x. So it's not enough to say 
 that only function declarations are immune to ordering rules.

Does being inside a function really make the type deduction any harder (or different?) than this?: auto b() { return a(); } enum X x = whatever; auto a() { return x; }
 Furthermore, any declaration before x, which calls b(), is using x even 
 though x hasn't been initialized (or even declared) yet. Suddenly all 
 kinds of horrible situations become possible, which could never happen 
 before.

(Don't know if this makes any sence, but I'm throwing it out there...) Suppose we did the approach I mentioned elsewhere in this thread: "the compiler rewrites nested func decls as delegate vars and anon funcs". Suppose we also use the rule: "A nested func is not *callable* (by either the parent function *or* another nested function) until after (ie "further down in the code") all the sibling symbols it accesses have been declared." If it's reasonable for type deduction to happen before all this (I have no idea how realistic that is), then with your example, the compiler first deduces the types just like it would outside a function: void foo() { X b() { return a(); } X x = whatever; X a() { return x; } } Then it gets rewritten: void foo() { delegate X() b; delegate X() a; b = X() { return a(); } X x = whatever; a = X() { return x; } } This would now be flagged as an error because "b" is calling "a" before (ie "earlier in the code than") all of the symbols "a" accesses (namely "x") have been declared. The following would also be an error for the same reason: void foo() { auto b() { return a(); } X w = b(); X x = whatever; auto a() { return x; } } However, this would still be perfectly ok: void foo() { X x = whatever; auto b() { return a(); } auto a() { return x; } } Because it turns into: void foo() { delegate X() b; delegate X() a; X x = whatever; b = X() { return a(); } a = X() { return x; } } And now, at the point in the code where "b" calls "a", everything "a" accesses (namely "x") has *already* been declared and inited. And of couse, "b" *can* call "a" because "a" is already declared way at the top.
Apr 03 2012
parent reply Don Clugston <dac nospam.com> writes:
On 03/04/12 11:24, Nick Sabalausky wrote:
 "Don Clugston"<dac nospam.com>  wrote in message
 news:jlecab$9gh$1 digitalmars.com...
 If you have type inference of function returns, things can get nasty:

 void foo()
 {
       auto b() { return a(); }
       X x = whatever;
       auto a() { return x; }
 }
 Now b actually depends on the declaration of x. So it's not enough to say
 that only function declarations are immune to ordering rules.

Does being inside a function really make the type deduction any harder (or different?) than this?: auto b() { return a(); } enum X x = whatever; auto a() { return x; }

Yes, it's different. In the second case, X is entirely determined at compile time. If you have multiple declarations, there are no user-visible semantics which are order-dependent; the value of the expression is independent of its location in the file. This is not true of declarations inside a scope: eg, static int count = 0; int order() { ++count; return count; } int x = order(); int y = order(); assert(x == 1); assert(y == 2);
 Furthermore, any declaration before x, which calls b(), is using x even
 though x hasn't been initialized (or even declared) yet. Suddenly all
 kinds of horrible situations become possible, which could never happen
 before.

(Don't know if this makes any sence, but I'm throwing it out there...) Suppose we did the approach I mentioned elsewhere in this thread: "the compiler rewrites nested func decls as delegate vars and anon funcs". Suppose we also use the rule: "A nested func is not *callable* (by either the parent function *or* another nested function) until after (ie "further down in the code") all the sibling symbols it accesses have been declared."

Difficult but doable, but I think you end up with a really funky rule. It's a morass of special cases.
Apr 03 2012
parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/3/2012 2:56 AM, Don Clugston wrote:
 Difficult but doable, but I think you end up with a really funky rule.
 It's a morass of special cases.

I agree with Don. And in the end, is a morass of complexity worth it to deal with one special case that is both unusual and has a reasonable workaround? I'd say no.
Apr 05 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/03/2012 10:27 AM, Don Clugston wrote:
 On 03/04/12 07:38, Nick Sabalausky wrote:
 Regarding this:

 http://d.puremagic.com/issues/show_bug.cgi?id=790

 I submit that nested functions should be exempt from the usual sequential
 visibility rules. (Therefore, mutually recursive nested functions would
 become possible.)

 Or at the very *least*, this horrific C-like workaround should be
 possible:

 void foo()
 {
      void b();
      void a() {...};
      void b() {...};
 }

 ...Flame away! ;)

This is asking for a complicated special case. In global scope, order of declarations doesn't matter. In function scope, order of declarations always matters. If you have type inference of function returns, things can get nasty: void foo() { auto b() { return a(); } X x = whatever; auto a() { return x; } } Now b actually depends on the declaration of x. So it's not enough to say that only function declarations are immune to ordering rules.

I come to a different conclusion. If only function declarations are immune to ordering rules, the above example is simply illegal. The example cannot be used to demonstrate incompleteness of the approach.
 Furthermore, any declaration before x, which calls b(), is using x even
 though x hasn't been initialized (or even declared) yet. Suddenly all
 kinds of horrible situations become possible, which could never happen
 before.

 In general, allowing forward references inside a function is far, far
 more difficult than in global scope.

If it is constrained enough, it shouldn't be more difficult.
 There are very many more special
 cases. Allowing it in global scope is quite complicated enough.

It should be possible to leverage the efforts spent there.
 You can always use a delegate, if you want recursive nested functions.

Templates are superior.
Apr 03 2012
parent reply Don Clugston <dac nospam.com> writes:
On 03/04/12 12:32, Timon Gehr wrote:
 On 04/03/2012 10:27 AM, Don Clugston wrote:
 On 03/04/12 07:38, Nick Sabalausky wrote:
 Regarding this:

 http://d.puremagic.com/issues/show_bug.cgi?id=790

 I submit that nested functions should be exempt from the usual
 sequential
 visibility rules. (Therefore, mutually recursive nested functions would
 become possible.)

 Or at the very *least*, this horrific C-like workaround should be
 possible:

 void foo()
 {
 void b();
 void a() {...};
 void b() {...};
 }

 ...Flame away! ;)

This is asking for a complicated special case. In global scope, order of declarations doesn't matter. In function scope, order of declarations always matters. If you have type inference of function returns, things can get nasty: void foo() { auto b() { return a(); } X x = whatever; auto a() { return x; } } Now b actually depends on the declaration of x. So it's not enough to say that only function declarations are immune to ordering rules.

I come to a different conclusion. If only function declarations are immune to ordering rules, the above example is simply illegal. The example cannot be used to demonstrate incompleteness of the approach.

I don't see a way to just declare it as "illegal". How would you detect that situation in the general case? It's not easy. Y b() { ... } Y y = b(); X x = ... Prove that y doesn't depend on x.
Apr 03 2012
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2012-04-03 11:08:38 +0000, Don Clugston <dac nospam.com> said:

 On 03/04/12 12:32, Timon Gehr wrote:
 On 04/03/2012 10:27 AM, Don Clugston wrote:
 This is asking for a complicated special case. In global scope, order of
 declarations doesn't matter. In function scope, order of declarations
 always matters.
 If you have type inference of function returns, things can get nasty:
 
 void foo()
 {
 auto b() { return a(); }
 X x = whatever;
 auto a() { return x; }
 }
 Now b actually depends on the declaration of x. So it's not enough to
 say that only function declarations are immune to ordering rules.

I come to a different conclusion. If only function declarations are immune to ordering rules, the above example is simply illegal. The example cannot be used to demonstrate incompleteness of the approach.

I don't see a way to just declare it as "illegal". How would you detect that situation in the general case? It's not easy. Y b() { ... } Y y = b(); X x = ... Prove that y doesn't depend on x.

You're right Don, it shouldn't be illegal. But it could be part of the constrain. Let's rephrase Timon's idea like this: If two or more functions declarations are following each other with no other statement in between, then these two functions can call one another. That could allow overloading too, as long as the declarations are following each other directly. In fact, that'd probably be generalizable to templates, struct, class, and enum declarations too. Adjacent declarations would create some kind of island in the function's code where order of declaration does not matter. The island ends at the first non-declaration statement or local variable declaration, and a new island begins when new declarations are encountered. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Apr 03 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/03/2012 01:08 PM, Don Clugston wrote:
 Y b() { ... }
 Y y = b();
 X x = ...

 Prove that y doesn't depend on x.

Since only function declarations are immune to ordering rules, b cannot forward reference x.
Apr 03 2012
parent reply Don Clugston <dac nospam.com> writes:
On 03/04/12 13:35, Timon Gehr wrote:
 On 04/03/2012 01:08 PM, Don Clugston wrote:
 Y b() { ... }
 Y y = b();
 X x = ...

 Prove that y doesn't depend on x.

Since only function declarations are immune to ordering rules, b cannot forward reference x.

But there could be another function a() which is below x, and which b() calls.
Apr 03 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/03/2012 01:55 PM, Don Clugston wrote:
 On 03/04/12 13:35, Timon Gehr wrote:
 On 04/03/2012 01:08 PM, Don Clugston wrote:
 Y b() { ... }
 Y y = b();
 X x = ...

 Prove that y doesn't depend on x.

Since only function declarations are immune to ordering rules, b cannot forward reference x.

But there could be another function a() which is below x, and which b() calls.

This scenario can be forbidden conservatively.
Apr 03 2012
parent reply Don Clugston <dac nospam.com> writes:
On 03/04/12 13:58, Timon Gehr wrote:
 On 04/03/2012 01:55 PM, Don Clugston wrote:
 On 03/04/12 13:35, Timon Gehr wrote:
 On 04/03/2012 01:08 PM, Don Clugston wrote:
 Y b() { ... }
 Y y = b();
 X x = ...

 Prove that y doesn't depend on x.

Since only function declarations are immune to ordering rules, b cannot forward reference x.

But there could be another function a() which is below x, and which b() calls.

This scenario can be forbidden conservatively.

How?
Apr 03 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/03/2012 02:08 PM, Don Clugston wrote:
 On 03/04/12 13:58, Timon Gehr wrote:
 On 04/03/2012 01:55 PM, Don Clugston wrote:
 On 03/04/12 13:35, Timon Gehr wrote:
 On 04/03/2012 01:08 PM, Don Clugston wrote:
 Y b() { ... }
 Y y = b();
 X x = ...

 Prove that y doesn't depend on x.

Since only function declarations are immune to ordering rules, b cannot forward reference x.

But there could be another function a() which is below x, and which b() calls.

This scenario can be forbidden conservatively.

How?

Don't allow forward referencing function a() if there is an intervening order-dependent declaration. (Alternatively, just analyse which symbols are referenced where and don't allow calling a local function that can transitively reach some symbols that have not yet been declared. I think this might be too complicated to be justifiable.)
Apr 03 2012
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Don Clugston" <dac nospam.com> wrote in message 
news:jlelnn$tm4$1 digitalmars.com...
 I don't see a way to just declare it as "illegal". How would you detect 
 that situation in the general case?
 It's not easy.

 Y b() { ... }
 Y y = b();
 X x = ...

 Prove that y doesn't depend on x.

We don't *have* to go the route of allowing nested functions to access forward-referenced variables. We could just limit it to forward-referenced nested functions. So this code could be illegal for exactly the same reason it's currently illegal: Y b() { /+ use the var 'x' +/ } Y y = b(); X x = ... If 'x' were a nested function instead of a variable, then *that* we could decide to start allowing: Y b() { /+ call function 'x' +/ } Y y = b(); X x() { ... } // b can access this because this is a nested func, not a var Of course, as you already pointed out and I replied to elsewhere in this thread, we'd still have to do something about this scenario: X b() { return a(); } X w = b(); X x = whatever; X a() { return x; } Alternatively, if I understand Timon right, I think he's suggesting that we could treat "groups" of nested function declarations as "unordered", and any one other statement/declaration would simply break the "group": // These three can all reference each other freely, // but they cannot reference f, x, y or z. A a() {...} B b() {...} C c() {...} // Something other than a nested function declaration. // This ends the "grouping" of a, b, and c. F f = ...; // These three can all reference each other freely. // Naturally, these can also reference a, b, c, and f X x() {...} Y y() {...} Z z() {...} That would allow mutual recursion while neatly avoiding any problems.
Apr 03 2012
parent Don Clugston <dac nospam.com> writes:
On 03/04/12 13:51, Nick Sabalausky wrote:
 "Don Clugston"<dac nospam.com>  wrote in message
 news:jlelnn$tm4$1 digitalmars.com...
 I don't see a way to just declare it as "illegal". How would you detect
 that situation in the general case?
 It's not easy.

 Y b() { ... }
 Y y = b();
 X x = ...

 Prove that y doesn't depend on x.

We don't *have* to go the route of allowing nested functions to access forward-referenced variables. We could just limit it to forward-referenced nested functions.

But it's the same. If you can forward reference a function, you can also access a variable. So this code could be illegal for exactly the same reason
 it's currently illegal:

 Y b() { /+ use the var 'x' +/ }
 Y y = b();
 X x = ...

 If 'x' were a nested function instead of a variable, then *that* we could
 decide to start allowing:

 Y b() { /+ call function 'x' +/ }
 Y y = b();
 X x() { ... } // b can access this because this is a nested func, not a var

 Of course, as you already pointed out and I replied to elsewhere in this
 thread, we'd still have to do something about this scenario:

 X b() { return a(); }
 X w = b();
 X x = whatever;
 X a() { return x; }

And I don't think there's any easy solution to that. I think it's a dead end.
 Alternatively, if I understand Timon right, I think he's suggesting that we
 could treat "groups" of nested function declarations as "unordered", and any
 one other statement/declaration would simply break the "group":

 // These three can all reference each other freely,
 // but they cannot reference f, x, y or z.
 A a() {...}
 B b() {...}
 C c() {...}

 // Something other than a nested function declaration.
 // This ends the "grouping" of a, b, and c.
 F f = ...;

 // These three can all reference each other freely.
 // Naturally, these can also reference a, b, c, and f
 X x() {...}
 Y y() {...}
 Z z() {...}

 That would allow mutual recursion while neatly avoiding any problems.

Yeah, that'd work. It's a funky rule though.
Apr 03 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/03/2012 07:38 AM, Nick Sabalausky wrote:
 Regarding this:

 http://d.puremagic.com/issues/show_bug.cgi?id=790

 I submit that nested functions should be exempt from the usual sequential
 visibility rules. (Therefore, mutually recursive nested functions would
 become possible.)

 Or at the very *least*, this horrific C-like workaround should be possible:

 void foo()
 {
      void b();
      void a() {...};
      void b() {...};
 }

 ...Flame away! ;)

This is the right way to work around this issue. It works now and does not imply any kind of overhead at runtime: void foo(){ void a()(){ ... } void b() { ... } } However, I agree. Local functions that appear directly in sequence should be able to forward-reference each other. If some functions appearing in such a sequence have identical names, they should overload against each other.
Apr 03 2012
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message 
news:jlej27$mvi$1 digitalmars.com...
 This is the right way to work around this issue. It works now and does not 
 imply any kind of overhead at runtime:

 void foo(){
     void a()(){ ... }
     void b()  { ... }
 }

That's a very simple workaround (albiet unintuitive - unless I'm just too tired right now). It leads me to two questions: 1. How the heck does that work? 2. What, if any, problems would arise from just automatically doing that behind-the-scenes? Ie, to just automatically turn all non-templated nested functions into no-parameter templated nested functions? Would that be a feasable solution?
Apr 03 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/03/2012 02:00 PM, Nick Sabalausky wrote:
 "Timon Gehr"<timon.gehr gmx.ch>  wrote in message
 news:jlej27$mvi$1 digitalmars.com...
 This is the right way to work around this issue. It works now and does not
 imply any kind of overhead at runtime:

 void foo(){
      void a()(){ ... }
      void b()  { ... }
 }

That's a very simple workaround (albiet unintuitive - unless I'm just too tired right now). It leads me to two questions: 1. How the heck does that work?

Symbol lookup is done upon the first instantiation of the local template.
 2. What, if any, problems would arise from just automatically doing that
 behind-the-scenes? Ie, to just automatically turn all non-templated nested
 functions into no-parameter templated nested functions? Would that be a
 feasable solution?

Your proposal is basically to allow a local function to forward reference any symbol that is declared before the local function is first referenced. This still has the following problem: void a(){/*cannot reference c*/} void b(){/*because this references a*/} void c(){/*references a and b*/ } It would work by reordering the code like so: void b(){/*references a*/} void a(){/*references c*/} void c(){/*references a and c*/} That would be extremely unintuitive.
Apr 03 2012
prev sibling next sibling parent "Martin Nowak" <dawg dawgfoto.de> writes:
 void foo(){
      void a()(){ ... }
      void b()  { ... }
 }

That's a very simple workaround (albiet unintuitive - unless I'm just too tired right now). It leads me to two questions: 1. How the heck does that work?

Symbol lookup is done upon the first instantiation of the local template.

I'd argue it shouldn't work, but it'd require copying the scope. instantiation scope -> declaration scope -> sequence snapshot So again b shouldn't be is a's scope.
Apr 03 2012
prev sibling parent "Xinok" <xinok live.com> writes:
On Tuesday, 3 April 2012 at 12:13:00 UTC, Timon Gehr wrote:
 On 04/03/2012 02:00 PM, Nick Sabalausky wrote:
 "Timon Gehr"<timon.gehr gmx.ch>  wrote in message
 news:jlej27$mvi$1 digitalmars.com...
 This is the right way to work around this issue. It works now 
 and does not
 imply any kind of overhead at runtime:

 void foo(){
     void a()(){ ... }
     void b()  { ... }
 }

1. How the heck does that work?

Symbol lookup is done upon the first instantiation of the local template.

Currently, it prints 365. But remove the commented line, and it prints 500 twice. But it's a minor issue at worst that's easy to avoid, and this is a very simple workaround. int two() { return 500; } void main() { int x = 365; int one()() { return two(); } // writeln(one()); int two() { return x; } writeln(one()); } I found another solution involving templates, though not as convenient: template foo() { int one(){ return two(); } int two(){ return x + y; } int y = 12; } void main() { int x = 365; mixin foo; writeln(one()); }
Apr 04 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Nick Sabalausky:

 I submit that nested functions should be exempt from the usual 
 sequential
 visibility rules. (Therefore, mutually recursive nested 
 functions would
 become possible.)

What about static nested functions? This seems a simpler enhancement request: import std.stdio; void main() { static int male(in int n) pure nothrow { return n ? (n - female(male(n - 1))) : 0; } static int female(in int n) pure nothrow { return n ? (n - male(female(n - 1))) : 1; } writeln(female(15)); } Bye, bearophile
Apr 03 2012
prev sibling parent reply Don Clugston <dac nospam.com> writes:
On 03/04/12 07:38, Nick Sabalausky wrote:
 Regarding this:

 http://d.puremagic.com/issues/show_bug.cgi?id=790

 I submit that nested functions should be exempt from the usual sequential
 visibility rules. (Therefore, mutually recursive nested functions would
 become possible.)

 Or at the very *least*, this horrific C-like workaround should be possible:

 void foo()
 {
      void b();
      void a() {...};
      void b() {...};
 }

 ...Flame away! ;)

The most flexible method is to declare a local, nested struct. Any member functions (and variables!) of that struct have non-sequential semantics, so they can forward reference each other just fine. void foo() { struct Local { static void a() { b(); } static void b() { }; } Local.a(); } If they need to access stack variables, you'll need to create an actual instance of the struct. You can make it a static struct if they don't need access to any stack variables of foo. Note that this completely sidesteps all the nasty issues I mentioned in other posts.
Apr 04 2012
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/4/2012 12:57 AM, Don Clugston wrote:
 The most flexible method is to declare a local, nested struct. Any member
 functions (and variables!) of that struct have non-sequential semantics, so
they
 can forward reference each other just fine.

Thanks, Don. I didn't think of this, and it's an awesome solution. Can you put it in the D FAQ?
Apr 05 2012
prev sibling parent "stas" <stasoid yahoo.com> writes:
 The most flexible method is to declare a local, nested struct.


It is a solution, but IMO it looks unpleasant. Reminds me C++, where I had to do this trick all the time.
 It's a morass of special cases.

If D had a notion of pure pure functions - pure functions without any "concessions to practicality" then we could consider this simple rule: "local pure pure functions can be forward referenced".
Oct 10 2012