On Tuesday, 31 May 2022 at 19:59:21 UTC, Steven Schveighoffer wrote:
>This is done on purpose.
What's the purpose? It looks like just another atavism, reproducing itself without any purpose.
May 31, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 31 May 2022 at 19:59:21 UTC, Steven Schveighoffer wrote: >This is done on purpose. What's the purpose? It looks like just another atavism, reproducing itself without any purpose. |
May 31, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ola Fosheim Grøstad | On 5/31/22 4:11 PM, Ola Fosheim Grøstad wrote: >On Tuesday, 31 May 2022 at 19:59:21 UTC, Steven Schveighoffer wrote: >Note that you can declare a prototype, but this also declares a symbol, and D does not allow you to redefine symbols. And this doesn't make any sense. Why would local functions not work like lambdas? Because they aren't lambdas. To use your example:
would be the same with lambdas as:
You can't "assign" functions like you can lambdas. And D does not allow redeclaring a symbol of any type in a specific scope. -Steve |
May 31, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Max Samukha | On 5/31/22 4:13 PM, Max Samukha wrote: >On Tuesday, 31 May 2022 at 19:59:21 UTC, Steven Schveighoffer wrote: >This is done on purpose. What's the purpose? It looks like just another atavism, reproducing itself without any purpose. To make code that is ported from C compile the same as it does in C. -Steve |
May 31, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 31 May 2022 at 20:24:17 UTC, Steven Schveighoffer wrote: >
This ought to define what has already been declared. That is the purpose of a prototype. Calling this a "redeclaration" is arbitrary. >would be the same with lambdas as:
This declares and defines foo. >You can't "assign" functions like you can lambdas. And D does not allow redeclaring a symbol of any type in a specific scope. Why do you call it "redeclaring" the signature is the same!? That's just an after-the-fact explanation. Calling this redeclaring doesn't follow from how prototypes in C works. If the signature is the same then you can do it as many times as you want. |
May 31, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ola Fosheim Grøstad | On 5/31/22 4:33 PM, Ola Fosheim Grøstad wrote: >On Tuesday, 31 May 2022 at 20:24:17 UTC, Steven Schveighoffer wrote: >
This ought to define what has already been declared. That is the purpose of a prototype. Calling this a "redeclaration" is arbitrary. I don't know why it does that, I assume Walter has a good reason for that. But they do work at module level (which is kinda weird, since you don't need them there). I had thought they weren't allowed. > >You can't "assign" functions like you can lambdas. And D does not allow redeclaring a symbol of any type in a specific scope. Why do you call it "redeclaring" the signature is the same!? That's just an after-the-fact explanation. Calling this redeclaring doesn't follow from how prototypes in C works. If the signature is the same then you can do it as many times as you want. I can't do:
So I assume it's similar to declaring functions, but I don't know the reason it allows this for function prototypes at the module level. -Steve |
May 31, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 31 May 2022 at 20:47:36 UTC, Steven Schveighoffer wrote: >So I assume it's similar to declaring functions, but I don't know the reason it allows this for function prototypes at the module level. Maybe he didn't think about mutual recursion. Anyway, this is legal in C++:
|
May 31, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 31 May 2022 at 19:59:21 UTC, Steven Schveighoffer wrote: >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; 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):
would work with scheme rules but
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:
what should print is "outer foo", because that is what Because D has chosen to define its version of lexical scoping in this way in this case, but not other cases. What you say would not be controversial if we were talking about
That doesn't work in D, Scheme or Haskell, nor should it, because the value of a variable not yet defined is required in the course of sequential evaluation of the statements above. But in the situation I encountered, the sequential evaluation is of function definitions. The forward reference is within one of those definitions and the actual reference does not occur until the function is invoked, at which point both functions have been defined and therefore I would expect foo and bar to be available to each other. What D is doing here makes no sense to me and is particularly bizarre because it does the opposite at top level and inside structs. >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. Well, I would argue that that kind of thinking leads to a language that is a collection of special cases, rather than a language built on a core set of principles consistently applied. Ok. I've had my say. I think this is a mistake, but I don't expect it to change because of my objection, so no point in pursuing. >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. My concern is not "solving this". My concern is whether the language is clean and consistent so I can have mental model of it I can rely upon, rather than constantly searching through documentation to learn how a particular special case is handled. I also care a lot about writing readable code, and about being able to limit the visibility of variables to just the scope that needs them and no more. The workarounds you cite frankly feel like hacks to me, ugly ways of working around problems in the language design. /Don >-Steve |
June 01, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Allen | On 31.05.22 19:41, Don Allen wrote:
>
> But
> ````
> import std.stdio;
>
> int main(string[] args)
> {
> void foo() {
> bar();
> }
> void bar() {
> writeln("Hello world");
> }
> foo();
> return 0;
> }
> ````
> gives the error
> ````
> (dmd-2.100.0)dca@pangloss.allen.net:/home/dca/Software/d_tests$ dmd test5.d
> test5.d(6): Error: undefined identifier `bar`
> ````
> This only works if you interchange the order of foo and bar, eliminating the
> forward reference.
>
> This strikes me as pretty inconsistent behavior
Not sure if it's necessarily "inconsistent", but it is quite annoying and not really necessary. I have also complained about this before.
The simplest workaround is to make `foo` a template:
```d
import std.stdio;
int main(string[] args){
void foo()(){
bar();
}
void bar(){
writeln("Hello world");
}
foo();
return 0;
}
```
|
June 01, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 31.05.22 22:24, Steven Schveighoffer wrote:
> On 5/31/22 4:13 PM, Max Samukha wrote:
>> On Tuesday, 31 May 2022 at 19:59:21 UTC, Steven Schveighoffer wrote:
>>
>>> This is done on purpose.
>>
>> What's the purpose? It looks like just another atavism, reproducing itself without any purpose.
>
> To make code that is ported from C compile the same as it does in C.
>
> -Steve
There are local functions in C?
|
May 31, 2022 Re: Puzzled by this behavior | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 5/31/22 8:17 PM, Timon Gehr wrote: >On 31.05.22 22:24, Steven Schveighoffer wrote: >On 5/31/22 4:13 PM, Max Samukha wrote: >On Tuesday, 31 May 2022 at 19:59:21 UTC, Steven Schveighoffer wrote: >This is done on purpose. What's the purpose? It looks like just another atavism, reproducing itself without any purpose. To make code that is ported from C compile the same as it does in C. There are local functions in C? I mean the lookup mechanisms are the same. But yeah, there are no local functions in C. I just figured that this is so the compiler doesn't have to have weird special cases for lookups. However, thinking about it more, we do allow function prototypes as local functions. But I can't figure out a way to actually define them, aside from using pragma(mangle). I think there's an opportunity here where we can allow function prototypes, allow definitions later, and not break existing code. -Steve |