Recent

Author Topic: Interleaving nested declarations with visibility specifiers  (Read 1538 times)

simone

  • Hero Member
  • *****
  • Posts: 573
Consider the following three examples. In all three cases, inside a class definition, two different visibility sections are opened, within a declaration of variables (Ex1), constants (Ex2) and types (Ex3). In the first case everything is fine for the compiler, in the other two cases it gives an error. Why this different behavior?

Code: Pascal  [Select][+][-]
  1. program Ex1;//Ok
  2. {$mode ObjFpc}
  3.  
  4. type
  5.   TMyClass = class
  6.   var
  7.   protected
  8.     Ident1: string;
  9.   private
  10.     Ident2: string;
  11.   end;
  12.  
  13. begin
  14. end.

Code: Pascal  [Select][+][-]
  1. program Ex2;//Error
  2. {$mode ObjFpc}
  3.  
  4. type
  5.   TMyClass = class
  6.   const
  7.   protected
  8.     Ident1=1;
  9.   private
  10.     Ident2=2;
  11.   end;
  12.  
  13. begin
  14. end.

Code: Pascal  [Select][+][-]
  1. program Ex3;//Error
  2. {$mode ObjFpc}
  3.  
  4. type
  5.   TMyClass = class
  6.   type
  7.   protected
  8.     Ident1=string;
  9.   private
  10.     Ident2=integer;
  11.   end;
  12.  
  13. begin
  14. end.
« Last Edit: May 10, 2022, 11:52:36 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Interleaving nested declarations with visibility specifiers
« Reply #1 on: May 11, 2022, 12:01:41 am »
I find it a bit surprising that Ex1 compiles because, the railroad diagrams show that "type", "var", "const", etc _follow_ the visibility specifier.  IOW, a visibility specifier isn't supposed to apply to "var", "type" and/or "const".

if you "tweaked" the declarations a little bit, it would compile fine and the semantics would not change, i.e :
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyClass = class
  3.   //var
  4.   protected
  5.   var
  6.     Ident1: string;
  7.   private
  8.   var
  9.     Ident2: string;
  10.   end;
  11.  
  12.  
  13. type
  14.     TMyClass2 = class
  15.     //const
  16.     protected
  17.     const
  18.       Ident1 = 1;
  19.     private
  20.     const
  21.       Ident2 = 2;
  22.     end;
  23.  
  24. type
  25.   TMyClass3 = class
  26.   //type
  27.   protected
  28.   type
  29.     Ident1=string;
  30.   private
  31.   type
  32.     Ident2=integer;
  33.   end;
  34.  

The fact that Ex1 compiles at all looks like a bug to me (at least it does not comply with the language's railroad diagrams/grammar at : https://www.freepascal.org/docs-html/ref/refse35.html#x70-940006.1


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

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Interleaving nested declarations with visibility specifiers
« Reply #2 on: May 11, 2022, 12:06:34 am »
I absolutely agree. I would have expected the first example not to be accepted by the compiler.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Interleaving nested declarations with visibility specifiers
« Reply #3 on: May 11, 2022, 12:13:40 am »
Obviously it makes more natural that var / const / type declarations are inside the public / protected / private visibility sections. I noticed this behavior while looking for a bug in a transpiler that I'm writing.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Interleaving nested declarations with visibility specifiers
« Reply #4 on: May 11, 2022, 08:22:36 pm »
The fact that Ex1 compiles at all looks like a bug to me (at least it does not comply with the language's railroad diagrams/grammar at : https://www.freepascal.org/docs-html/ref/refse35.html#x70-940006.1
Probably because the var block is implicit. I.e. if not explicitly specified, "public var" is used by default.
By the way, the diagram does not show how a block of variables is defined. Only in the section about fields it is written that it can be defined implicitly or explicitly in the var block.
Interestingly, the behavior of Delphi exactly repeats FPC - the first example compiles successfully, the rest do not.

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Interleaving nested declarations with visibility specifiers
« Reply #5 on: May 11, 2022, 09:23:35 pm »
Interestingly, the behavior of Delphi exactly repeats FPC - the first example compiles successfully, the rest do not.
That's strange.  I wonder what causes the compiler to see "var protected <etc>" as a valid construct.

At least it's "Delphi compatible" <chuckle>

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

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Interleaving nested declarations with visibility specifiers
« Reply #6 on: May 11, 2022, 10:10:49 pm »
Implicit is var or method definitions (but if there are field definitions then before the method definitions)

So

Code: Pascal  [Select][+][-]
  1. type
  2.   TMyClass = class
  3.  
  4.   protected
  5.      Ident1: string;
  6.      procedure x1;
  7.   private
  8.  
  9.     Ident2: string;
  10.     procedure y1;
  11.   end;
  12.  


but if you change order, you need to pay attention and/or add var's.
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyClass = class
  3.  
  4.   protected
  5.      procedure x1;
  6.      Ident1: string;
  7. // then you need (untested)
  8.   private
  9.     procedure y1;
  10.    var  // required otherwise won't compile
  11.     Ident2: string;
  12.   end;
  13.  
« Last Edit: May 13, 2022, 02:42:39 pm by marcov »

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Interleaving nested declarations with visibility specifiers
« Reply #7 on: May 12, 2022, 09:17:33 am »
Interestingly, the behavior of Delphi exactly repeats FPC - the first example compiles successfully, the rest do not.

The Delphi 10.2 I have also compiles the empty const and type sections.

Interestingly, the behavior of Delphi exactly repeats FPC - the first example compiles successfully, the rest do not.
That's strange.  I wonder what causes the compiler to see "var protected <etc>" as a valid construct.

The compiler sees an empty var section followed by the next visibility section. It's done this way, because empty visibility sections were already allowed from the beginning of the class concept (which are implicitly var)

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Interleaving nested declarations with visibility specifiers
« Reply #8 on: May 12, 2022, 07:42:09 pm »
The compiler sees an empty var section followed by the next visibility section. It's done this way, because empty visibility sections were already allowed from the beginning of the class concept (which are implicitly var)
Thank you for clarifying that. 

I still find it strange that the compiler accepts an empty "var" declaration.  In the common case an empty "var" declaration is rejected e.g, "var begin end." OTOH, I realize that if Delphi accepts an empty "var" declaration when it is followed by a visibility specifier then for compatibility reasons, it should probably stay that way.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Interleaving nested declarations with visibility specifiers
« Reply #9 on: May 13, 2022, 02:23:10 pm »
The Delphi 10.2 I have also compiles the empty const and type sections.
Delphi 10.4. Screen attached.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Interleaving nested declarations with visibility specifiers
« Reply #10 on: May 16, 2022, 02:01:34 pm »
The Delphi 10.2 I have also compiles the empty const and type sections.
Delphi 10.4. Screen attached.

I see what the issue is, cause I wasn't clear enough.. :-X

So the code tested by you and originally provided by simone for the const and type cases is simply wrong, because the order is first the visibility section (if any, default is either public or published depending on $M) and then the type of the section (with default being var).
What I meant however is an empty var, const or type section followed by a visibility specifier and then followed by some entry for a var section (because a visibility specifier always starts a new section which is var if nothing else is mentioned). This compiles in both FPC and Delphi (so nothing to fix here either).

 

TinyPortal © 2005-2018