View mode: basic / threaded / horizontal-split · Log in · Help
April 03, 2012
Nested functions should be exempt from sequential visibility rules
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! ;)
April 03, 2012
Re: Nested functions should be exempt from sequential visibility rules
> 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
April 03, 2012
Re: Nested functions should be exempt from sequential visibility rules
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 .
April 03, 2012
Re: Nested functions should be exempt from sequential visibility rules
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.
April 03, 2012
Re: Nested functions should be exempt from sequential visibility rules
"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.
April 03, 2012
Re: Nested functions should be exempt from sequential visibility rules
"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.
April 03, 2012
Re: Nested functions should be exempt from sequential visibility rules
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.
April 03, 2012
Re: Nested functions should be exempt from sequential visibility rules
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.
April 03, 2012
Re: Nested functions should be exempt from sequential visibility rules
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.
April 03, 2012
Re: Nested functions should be exempt from sequential visibility rules
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.
« First   ‹ Prev
1 2 3
Top | Discussion index | About this forum | D home