Recent

Author Topic: A doubt about the visibility specifiers in the classes  (Read 993 times)

simone

  • Hero Member
  • *****
  • Posts: 573
A doubt about the visibility specifiers in the classes
« on: July 26, 2022, 10:17:49 am »
Consider the following program and the unit it uses:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$mode ObjFPC}{$H+}
  3. uses unit1;
  4. var
  5.   MyClass : TMyClass;
  6.  
  7. begin
  8.   MyClass:=TMyClass.Create;
  9.   MyClass.Test(Value1);
  10.   MyClass.Free;
  11. end.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2. {$mode ObjFPC}{$H+}
  3.  
  4. interface
  5. uses
  6.   Classes, SysUtils;
  7. type
  8.  
  9.   TMyClass=class
  10.     private
  11.       type
  12.         TMyEnum=(Value1,Value2);
  13.     public
  14.       procedure Test(MyEnum : TMyEnum);
  15.   end;
  16.  
  17. implementation
  18.  
  19. procedure TMyClass.Test(MyEnum: TMyEnum);
  20. begin
  21.   writeln(MyEnum);
  22. end;
  23.  
  24. end.

In the Unit1, TMyEnum is an enum type declared in private section of TMyClass, so it should only be visible in the module that contains the class definition.
Nevertheless in the main program I can use the values of TMyEnum as parameters to invoke the Test method of the same class.

This is also possible if strict private is used.

Why are the values of TMyEnum visible outside the module, even though they have been declared as (strict) private in the class they belong to?

Thanks in advance for the kind explanations.

« Last Edit: July 26, 2022, 10:29:59 am by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: A doubt about the visibility specifiers in the classes
« Reply #1 on: July 26, 2022, 10:32:12 am »
It is a bit contrived having a public method with a private type.  How do you imagine that this would work?

Can you access the values (e.g. ord()ing) without declaring that method? Maybe the method causes the enum to be exported.

simone

  • Hero Member
  • *****
  • Posts: 573
Re: A doubt about the visibility specifiers in the classes
« Reply #2 on: July 26, 2022, 10:35:23 am »
I'm not saying this is good programming practice, but since it's allowed, I'd just like to understand why the compiler behaves this way.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

Thaddy

  • Hero Member
  • *****
  • Posts: 14211
  • Probably until I exterminate Putin.
Re: A doubt about the visibility specifiers in the classes
« Reply #3 on: July 26, 2022, 10:47:13 am »
Because the public test method is an access specifier?
It would be different if the enum itself is accessible directly from other units without an access specifier or even with strict private from the same unit: in that case it is a bug. But it isn't. The method 'exports' it because of its parameter.
« Last Edit: July 26, 2022, 10:52:14 am by Thaddy »
Specialize a type, not a var.

simone

  • Hero Member
  • *****
  • Posts: 573
Re: A doubt about the visibility specifiers in the classes
« Reply #4 on: July 26, 2022, 11:04:35 am »
Thanks Thaddy. So should I assume that a public method of a class makes public the types of its parameters that have been declared private in the same class?

Post Scriptum: It's obvious that the example does not show a good style of programming. I exemplified a situation that happened to me during a refactoring, in which certain edge situations like this can occur.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: A doubt about the visibility specifiers in the classes
« Reply #5 on: July 26, 2022, 11:30:11 am »
Post Scriptum: It's obvious that the example does not show a good style of programming. I exemplified a situation that happened to me during a refactoring, in which certain edge situations like this can occur.

I think this is something that the compiler could usefully warn about, but is quite simply such an absurdity (in the strictly logical sense) that it can be forgiven for overlooking it.

Do you have a more concrete example?

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

simone

  • Hero Member
  • *****
  • Posts: 573
Re: A doubt about the visibility specifiers in the classes
« Reply #6 on: July 26, 2022, 11:53:57 am »
I have a more concrete example, but it comes from too large a code base to show here. In brief, as part of a refactoring process, I reorganized some classes and had an unexpected outcome that made me discover this behavior.

I just wanted to know if it was known and expected. For me, modestly, it was not an expected behavior. That's all.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

kupferstecher

  • Hero Member
  • *****
  • Posts: 583
Re: A doubt about the visibility specifiers in the classes
« Reply #7 on: July 26, 2022, 12:17:24 pm »
Here is a simple test that might be related to the issue, see below. There are no classes involved, but a (record) type that is defined in an other unit (unit uTypes). The type is the result of a function implemented in Unit1. Obviously uTypes needs to be added to "uses" in that unit. Unit2 uses the function of unit1 and can access the result type even if uTypes is not added to "uses", see the code of unit2, especially the comments. I think its useful.

project1.lpr:
Code: Pascal  [Select][+][-]
  1. program project1;
  2. uses Unit1, uTypes, Unit2;
  3. begin
  4.   WriteSth;
  5.   ReadLn;
  6. end.  

unit1.pas:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2. {$mode ObjFPC}{$H+}
  3. INTERFACE
  4.  
  5. uses uTypes;
  6.  
  7. Function GetValue: TSth;
  8.  
  9. IMPLEMENTATION
  10.  
  11. Function GetValue:TSth;
  12. begin
  13.   Result.one:= 1;
  14.   Result.two:= 2;
  15. end;
  16.  
  17. end.

unit2.pas:
Code: Pascal  [Select][+][-]
  1. unit Unit2;
  2. {$mode ObjFPC}{$H+}
  3. INTERFACE
  4.  
  5. uses Unit1;
  6.  
  7. Procedure writeSth;
  8.  
  9. IMPLEMENTATION
  10.  
  11. Procedure writeSth;
  12. //var res: TSth; //not possible, if uTypes is not in uses
  13. begin
  14.   writeln('Value: ',GetValue.two); //record member can be accessed without uTypes in "uses"
  15. end;
  16.  
  17. end.

uTypes.pas:
Code: Pascal  [Select][+][-]
  1. unit uTypes;
  2. {$mode ObjFPC}{$H+}
  3. INTERFACE
  4.  
  5. Type TSth = record
  6.   one: Integer;
  7.   two: Integer;
  8. end;
  9.  
  10. IMPLEMENTATION
  11.  
  12. end.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: A doubt about the visibility specifiers in the classes
« Reply #8 on: July 26, 2022, 12:39:20 pm »
Here is a simple test that might be related to the issue, see below. There are no classes involved, but a (record) type that is defined in an other unit (unit uTypes). The type is the result of a function implemented in Unit1. Obviously uTypes needs to be added to "uses" in that unit. Unit2 uses the function of unit1 and can access the result type even if uTypes is not added to "uses", see the code of unit2, especially the comments. I think its useful.

I'd suggest that there's a big difference between "needs to be added to 'uses'" and "is automatically made public" which is what OP was demonstrating.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

kupferstecher

  • Hero Member
  • *****
  • Posts: 583
Re: A doubt about the visibility specifiers in the classes
« Reply #9 on: July 26, 2022, 12:57:56 pm »
I'd suggest that there's a big difference between "needs to be added to 'uses'" and "is automatically made public" which is what OP was demonstrating.

Agreed, but I don't see that the OP demonstarted that the type itself was automatically made public[1], but only that the enum identifiers were made public. And I see the enum identifiers similar to the record member identifiers.

Then it seems these identifiers are automatically made available by the compiler if the type is used as parameter. And "making it available" in the one case is like making it public and in the other case like beeing added to uses.

[1]
If you try to add
Code: Pascal  [Select][+][-]
  1. var enum: TMyEnum;
in project1.lpr then it will fail:
project1.lpr(6,9) Error: Identifier not found "TMyEnum"

simone

  • Hero Member
  • *****
  • Posts: 573
Re: A doubt about the visibility specifiers in the classes
« Reply #10 on: July 26, 2022, 01:18:07 pm »

.... I don't see that the OP demonstarted that the type itself was automatically made public[1], but only that the enum identifiers were made public. And I see the enum identifiers similar to the record member identifiers.

Then it seems these identifiers are automatically made available by the compiler if the type is used as parameter. And "making it available" in the one case is like making it public and in the other case like beeing added to uses.


Yes you are right. The enum type is not made public, but the identifiers used in its definition.

Honestly, I'm not sure this behavior is consistent. However, I leave the judgment to more authoritative people.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: A doubt about the visibility specifiers in the classes
« Reply #11 on: July 26, 2022, 02:01:17 pm »
Why are the values of TMyEnum visible outside the module, even though they have been declared as (strict) private in the class they belong to?

It might be that enums and nested types might bite each other a bit here, due how they are to behave in TP and Delphi without nested types. I'll need to crosscheck with those two to decide on what is right and what is wrong.

 

TinyPortal © 2005-2018