Puzzled by this behavior

Steven Schveighoffer schveiguy at gmail.com
Tue May 31 19:59:21 UTC 2022


On 5/31/22 2:30 PM, Don Allen wrote:
> On Tuesday, 31 May 2022 at 17:52:35 UTC, Adam D Ruppe wrote:
>> On Tuesday, 31 May 2022 at 17:41:18 UTC, Don Allen wrote:
>>> This strikes me as pretty inconsistent behavior
>>
>> Code in functions is actually executed in sequence. Nested functions 
>> aren't exactly code, but the same rule applies to them. Consider:
>>
>> int a = 5;
>> a = 6;
>> int b = a;
>>
>> What is b? Of course we know since it happens in sequence. Same rule 
>> applies with nested functions.
>>
>>> I've also not found it documented, though I could have missed it (if 
>>> someone could point me to where this is discussed, I'd
>>
>> It has its own section on the function page:
>>
>> https://dlang.org/spec/function.html#nested-declaration-order
> 
> Code in Scheme functions are also evaluated in sequence, but functions 
> can be mutually recursive whether at top-level or not, so the mere fact 
> of sequential evaluation is not the explanation.

The scheme code likely evaluates the *definition* of the function, 
without resolving what *code* to call until it encounters a call.

In other words, something like this in D (I haven't used scheme in a 
while, so we are going to use D syntax):

```d
void foo() { bar(); }
void bar() { writeln("hello"); }
foo();
```

would work with scheme rules but

```d
void foo() { bar(); }
foo();
void bar() { writeln("hello"); }
```

would not.

> What appears to matter 
> is when the location of called functions are resolved -- compile-time 

It's not a matter of when they are resolved. D is fully capable of 
resolving functions at compile time out of order. It's a question of 
what symbols *are in scope*.

Consider:

```d
void foo() { writeln("outer foo"); }


void main()
{
    void bar() { foo(); }
    void foo() { writeln("inner foo"); }
    bar();
}
```

what should print is "outer foo", because *that* is what `foo` means at 
the point in which bar is being compiled. Inside functions, order of 
declaration is important and significant. Outside functions, they can be 
in any order, but must not be ambiguous. These are incompatible sets of 
rules. You have to pick one, and D chose to pick C rules inside 
functions (likely for compatibility), but allowed out of order 
declarations outside them because prototyping is just monotonous.

This is done on purpose. The easiest way to solve this is to declare the 
functions inside a struct in the function (as the workarounds suggest). 
I've done this many times when I have a significantly complex recursive 
algorithm that I don't want to expose outside the function.

Note that you can declare a prototype, but this also declares a symbol, 
and D does not allow you to redefine symbols.

-Steve


More information about the Digitalmars-d mailing list