Recent

Author Topic: Nested declarations inside advanced record  (Read 22046 times)

440bx

  • Hero Member
  • *****
  • Posts: 4984
Re: Nested declarations inside advanced record
« Reply #45 on: January 14, 2025, 02:24:16 am »
Wonderful... no only you can type a bunch of garbage in your posts, you can write garbage code too.  You really are impressively talented.

That said, you still haven't explained why Pascal compilers (that don't include code from you... LOL) emit a "duplicate identifier" error message.  The reason is genuinely trivial.

Aren't you tired of demonstrating you have no concept whatsoever of language design and compiler construction ?.  For the love of god, read Per Brinch Hansen On Pascal Compilers, it's an introductory book, really easy to read and he explains everything in detail.  He even draws how scopes operate and explains why.

Stop posting misleading garbage and start learning.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Khrys

  • Full Member
  • ***
  • Posts: 147
Re: Nested declarations inside advanced record
« Reply #46 on: January 14, 2025, 08:24:26 am »
Ok, so here's my theory to hopefully settle this once and for all:

Parameters and local variables are in different (albeit nested) scopes, and FPC explicitly disallows shadowing the former through a special check in  symtable.pas  (see Warfley's post).
This means that the "duplicate identifier" error message is a misnomer in this case; being an exception to the usual rules (shadowing generally being allowed), it should be marked as such.

Take the previous example:

Code: Pascal  [Select][+][-]
  1. procedure Foo(X: Integer);      // ---------+
  2. var                             // Foo:     |--------+
  3.   X: Integer;                   // Intf.    | Foo:   |
  4. begin                           // (Params) | Impl.  |
  5.   {Does not compile}            //          | (Body) |
  6. end;                            // ---------+--------+

Now let's change  X  to  Y  and add a nested function:

Code: Pascal  [Select][+][-]
  1. procedure Foo(X: Integer);      // ---------+
  2.   procedure Bar(W: Integer);    // Foo:     |----------+
  3.   var                           // Intf.    | Bar:     |--------+
  4.     Z: Double;                  // (Params) | Intf.    | Bar:   |
  5.   begin                         //          | (Params) | Impl.  |
  6.     {"X" -> Foo.X}              //          |          | (Body) |
  7.     {"Y" is not accessible}     //          |          |        |
  8.   end;                          //          |----------+--------+
  9. var                             //          |--------+
  10.   Y: String;                    //          | Foo:   |
  11. begin                           //          | Impl.  |
  12.   {Compiles just fine}          //          | (Body) |
  13. end;                            // ---------+--------+

The nested function can access the enclosing function's parameter X, but not its local variable Y, as it is declared separately.
It's also interesting to note that renaming  W  to  X  doesn't produce an error and simply shadows the enclosing function's parameter of the same name, while being in the same location that caused an error in the previous example; renaming  Z  to  X  also works flawlessly.

440bx

  • Hero Member
  • *****
  • Posts: 4984
Re: Nested declarations inside advanced record
« Reply #47 on: January 14, 2025, 09:05:28 am »
Ok, so here's my theory to hopefully settle this once and for all:

Parameters and local variables are in different (albeit nested) scopes, and FPC explicitly disallows shadowing the former through a special check in  symtable.pas  (see Warfley's post).
This means that the "duplicate identifier" error message is a misnomer in this case; being an exception to the usual rules (shadowing generally being allowed), it should be marked as such.
This is truly unbelievable.

Parameters and local variables are in the same scope, this is obvious because if they weren't in the same scope then one of them would need to be prefixed with a scope identifier, i.e., <scope identifier>.<(parameter or local variable) identifier> depending on which one is incorrectly considered to be outside the function/procedure block.

The "duplicate identifier" is in no way a misnomer.  That's completely absurd. 

However FPC implements its scope resolution is as irrelevant to scope resolution as the color of the Pope's underwear on Tuesdays. 

Does anyone really think that Delphi, Gnu Pascal, UCSD Pascal, etc, etc, use the same algorithms and code as FPC ? really ???? Stop inhaling red paint for breakfast, it's not good for you.   

Reading FPC's source code doesn't teach basic language design and implementation principles.  FPC doesn't even show which production its parser code implements. 

Read PBH's books, Pemberton's comments on P4 (or P5, don't remember which one it addresses right now) and, if you want to see the source of a well written compiler, read PBH's SuperPascal's source code.   

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Khrys

  • Full Member
  • ***
  • Posts: 147
Re: Nested declarations inside advanced record
« Reply #48 on: January 14, 2025, 10:47:04 am »
Parameters and local variables are in the same scope [...]

Why can  Bar  access  Foo's parameter  X  but not its local variable  Y  then?

440bx

  • Hero Member
  • *****
  • Posts: 4984
Re: Nested declarations inside advanced record
« Reply #49 on: January 14, 2025, 12:27:24 pm »
Parameters and local variables are in the same scope [...]

Why can  Bar  access  Foo's parameter  X  but not its local variable  Y  then?
You know the answer to that: because Y is defined _after_ procedure Bar. As I have no doubt you know, Pascal requires all identifiers to be defined before they can be accessed.

Here is your code slightly modified to illustrate some cases (Note that "Y" is still in Foo but it's declared sooner):
Code: Pascal  [Select][+][-]
  1.  
  2. procedure Foo(X: Integer);      // ---------+
  3. var
  4.   Y : String;
  5.  
  6.   procedure Bar(W: Integer);    // Foo:     |----------+
  7.   var                           // Intf.    | Bar:     |--------+
  8.     Z : Double;                 // (Params) | Intf.    | Bar:   |
  9.  
  10.  
  11.     X : byte;        { masks (or shadows if you prefer) the parameter X }
  12.  
  13.   begin                         //          | (Params) | Impl.  |
  14.     {"X" -> Foo.X}              //          |          | (Body) |
  15.     {"Y" is not accessible}     //          |          |        |
  16.  
  17.  
  18.     X := 355;         { will emit a warning if X (in bar) exists, won't otherwise }
  19.  
  20.                       { --------------- }
  21.     Y := '';          { access Y in Bar }
  22.                       { --------------- }
  23.  
  24.   end;                          //          |----------+--------+
  25. //var                             //          |--------+
  26. //  Y: String;                    //          | Foo:   |
  27. begin                           //          | Impl.  |
  28.   {Compiles just fine}          //          | (Body) |
  29. end;                            // ---------+--------+
  30.  
Now Bar can access Y without any problem.

In the above, the local variable "X" in Bar masks (or shadows if you prefer) Foo's parameter "X".  Here is a little experiment I'd like you to do: compile the above code and you'll get a warning stating that the value of "X" is out of range (355 is larger than what fits in a byte), that proves that the compiler is using the definition "X : byte".  After that, comment out the definition "X : byte" and recompile.  Note that the warning will be gone proving that it is the parameter "X" that is being accessed. 

The local "X : byte" and parameter "X : integer" are most definitely NOT in the same scope but, "W" and "Z" are most definitely in the _same_ scope.  the same way that the parameter "X" and local variable "Y" are also in the same scope (just  in case, a different scope than the one that contains "W" and "Z".)

Scoping is very nicely explained in PBH's book as well as a simple yet effective and fully functional implementation.  I've recommended PBH's book for years precisely because it focuses on the concepts, gives clear explanations and fairly simple implementations that are easy to understand and they work.   

To be fair, he did cut a few corners here and there but not in concepts.  That's fair because he clearly states in the introduction, it's a book meant as a basic introduction to language grammars and compiler construction.   It's an introductory course.

Also and likely very important in this discussion, in Pascal the scope resolution implementation always accounts for nested scopes but that doesn't mean that in the code:
Code: Pascal  [Select][+][-]
  1.  procedure foo(x: Integer);
  2. var
  3.   x: Double;
  4. begin
  5. end;
that the parameter "x" and local variable "x" are in different scopes, they are not, they are in the same scope.  However, there is no doubt in my mind that the code that handles that simple case is the very same code that handles nested scopes since "procedure foo" is nested in the program, therefore defines a nested scope.

IOW, it is completely incorrect to conclude that because the code can handle nested scopes that somehow parameter "x" and local variable "x" are different scopes.  Again: parameter "x" and local variable "x" are in the same scope. which is why the compiler emits a "duplicate identifier" message.


(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 1863
Re: Nested declarations inside advanced record
« Reply #50 on: January 14, 2025, 12:53:28 pm »
That said, you still haven't explained why Pascal compilers (that don't include code from you... LOL) emit a "duplicate identifier" error message.  The reason is genuinely trivial.
Interesting, so do you say that the FPC is a pascal compiler only if it doesn't contain code by me? If so, I'm sorry to tell you but the FPC already contains code by me since 2023 :)

440bx

  • Hero Member
  • *****
  • Posts: 4984
Re: Nested declarations inside advanced record
« Reply #51 on: January 14, 2025, 01:02:30 pm »
Interesting, so do you say that the FPC is a pascal compiler only if it doesn't contain code by me? If so, I'm sorry to tell you but the FPC already contains code by me since 2023 :)
No, what I am saying is that a Pascal compiler is significantly more likely to function correctly (and sensibly) if it doesn't contain code from you. 


(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 1863
Re: Nested declarations inside advanced record
« Reply #52 on: January 14, 2025, 01:13:18 pm »
However FPC implements its scope resolution is as irrelevant to scope resolution as the color of the Pope's underwear on Tuesdays. 

Does anyone really think that Delphi, Gnu Pascal, UCSD Pascal, etc, etc, use the same algorithms and code as FPC ? really ???? Stop inhaling red paint for breakfast, it's not good for you.   

Again your problem is you lack a consistent definition of what a scope is. What is a definition that encompasses what you are talking about?

Like let's take the description of scope from Niklaus Wirth in his book Compiler Construction:
Quote
The symbol table consists of lists of elements, one for each scope (see Section 8.2). The
elements consist of the name (identifier) and a reference to the identified object.
Code: Pascal  [Select][+][-]
  1. Ident = POINTER TO IdentDesc;
  2. IdentDesc = RECORD name: ARRAY 32 OF CHAR;
  3. obj: Object; next: Ident
  4. END ;
  5. Scope = POINTER TO ScopeDesc;
  6. ScopeDesc = RECORD first: Ident; dsc: Scope; END;
Here the definition of a scope is completely practical, a scope is just an entry in the stack of symbol lists that form the symbol table.
But according to that, in FPC, which is it's own pascal dialect (there is no "true" pascal, each compiler provides their own dialect with their own rules), parameters and variables are in different scopes.

But you could also go with a more formal definition, like is alluded to in the book by brinch hansen, that a scope is a set of rules according to which symbols are resolved. This is a very useful definition for formal analysis, but then any new declaration creates a new scope, because it is only referencable after it's declaration.

This is also a correct way to define scopes, it's not useful for implementing a compiler, but if you do formal analysis of a program (like I have done in my research job in the past), this is how you will mathematically model the scopes.

So there is a practical way to define scopes, as the structuring of the symbol table, and a mathematical definition of scopes used in formal analysis. I have seen both in practice, I have used both for real world applications, they are both equally valid for different purposes. But crucially according to both of these definitions you are wrong

440bx

  • Hero Member
  • *****
  • Posts: 4984
Re: Nested declarations inside advanced record
« Reply #53 on: January 14, 2025, 02:04:42 pm »
Again your problem is you lack a consistent definition of what a scope is. What is a definition that encompasses what you are talking about?
No, that is your problem.  I _showed_ you what a scope is and encompasses by referring to PBH's chapter on scoping where he even draws the scopes and what they contain. 

The concept of scope is totally independent of how it is implemented and what you showed there is a very limited definition of a possible implementation. 

Of course, you'll keep posting trash because you don't want to concede that for two identifiers to be considered duplicates they must reside in the same scope.  That fact, is totally independent of how scope resolution is implemented.

In the following code:
Code: Pascal  [Select][+][-]
  1.  procedure foo(x: Integer);
  2. var
  3.   x: Double;
  4. begin
  5. end;
You are yet to explain why the compiler emits a duplicate identifier message.  It's really simple and by now I've lost count of the number of times I've explained why to you (and, unfortunately also had to explain it to a forum member you've confused with your garbage.)


(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Khrys

  • Full Member
  • ***
  • Posts: 147
Re: Nested declarations inside advanced record
« Reply #54 on: January 14, 2025, 02:08:19 pm »
Here is your code slightly modified [...]

Irrelevant. This exact code is a counterexample to your claim, using the definition of a scope from Brinch Hansen on Pascal compilers6.2 SCOPE RULES  (page 107 of the .pdf):

Quote from: Brinch Hansen on Pascal Compilers
We must also specify in which part of a block an object can be referenced. This part of the block is called the scope of the object. An object is said to be known in its scope.

So the scope of an object is the part of the block in which it can be referenced.

Parameter  X  can be referenced inside  Bar.
Local variable  Y  can not be referenced inside  Bar.
Therefore the scope of  X  differs from the scope of  Y.

(I'd even go so far as to say that two different objects can never share the same scope, as that would imply that they are the same object.)

440bx

  • Hero Member
  • *****
  • Posts: 4984
Re: Nested declarations inside advanced record
« Reply #55 on: January 14, 2025, 02:20:50 pm »
Local variable  Y  can not be referenced inside  Bar.
That is so ridiculous, it's unbelievable.

In your example "Y" couldn't be referenced because it had not been defined.  It's not a matter of scopes, it's a matter of definition sequence.  Unbelievable!!!

The sad part is that you've got all that Warfley trash in your head.    He is beyond help and it looks like you are in that boat too.  Oh well.

The two of you should get a room, make each happy... LOL

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Khrys

  • Full Member
  • ***
  • Posts: 147
Re: Nested declarations inside advanced record
« Reply #56 on: January 14, 2025, 03:00:49 pm »
In your example "Y" couldn't be referenced because it had not been defined.  It's not a matter of scopes, it's a matter of definition sequence.  Unbelievable!!!

May I remind you that the question was whether parameters and locals share the same scope?

It doesn't matter how or why  Y  is unable to be referenced. I took a formal definition of what a scope is (from a source you gave) and showed via counterexample that parameters and locals do not in fact share the same scope, all in 4 lines of simple English. If that's too much for you to comprehend, then I'm afraid I can't help you.

I'm leaving this discussion to touch some grass.

ASerge

  • Hero Member
  • *****
  • Posts: 2374
Re: Nested declarations inside advanced record
« Reply #57 on: January 14, 2025, 06:17:23 pm »
I agree with @440bx that the scope of the function parameters is the same as the scope of the local variables of this function. And this is not only in FPC, but also in other languages.
In the implementation of the FPC compiler, symbol tables for local variables and symbol tables for parameters were separated only for check duplication on the names of properties and method parameters in the class. Formally, they are from different scopes, but the FPC compiler has implemented this additional protection.
And the fact that @Warfley was able to hack the implementation of the compiler to cancel the correct check does not change the situation.

Thaddy

  • Hero Member
  • *****
  • Posts: 16520
  • Kallstadt seems a good place to evict Trump to.
Re: Nested declarations inside advanced record
« Reply #58 on: January 14, 2025, 07:02:29 pm »
It may be scope on the same level, but it is not the same scope.
But I am sure they don't want the Trumps back...

Warfley

  • Hero Member
  • *****
  • Posts: 1863
Re: Nested declarations inside advanced record
« Reply #59 on: January 14, 2025, 07:38:44 pm »
In the implementation of the FPC compiler, symbol tables for local variables and symbol tables for parameters were separated only for check duplication on the names of properties and method parameters in the class.
No parameters are in a different symtable for many more reasons, most importantly to match forward declarations. When the compiler finds a local implementation of a procedure, it checks if it has already found a forward declaration that contains the same symbols, as in ObjFPC not just the signature must be identical but the symbols must be identical:
Code: Pascal  [Select][+][-]
  1. procedure Foo(i: Integer); forward;
  2. procedure Foo(j: Integer);
  3. begin
  4. end;
This is not allowed in Pascal, unlike in other languages like in C.

Also parameters are visible to the callsite of a function:
Code: Pascal  [Select][+][-]
  1. procedure Foo(var i: Integer);
  2. begin
  3. end;
  4.  
  5. begin
  6.   Foo(42);
  7. end.
This throws an error because 42 is not a variable, how does the compiler know that? By looking up the parameter of the function call. Therefore the parameter must be visible at the callsite, note that the compiler does not have access to any information of local variables at the callsite.

They have different visibilities, different naming rules, different restrictions, and are technically in a different symtable. How does any of that apply to local variables?
« Last Edit: January 14, 2025, 07:40:39 pm by Warfley »

 

TinyPortal © 2005-2018