Recent

Author Topic: [Solved] Why identifier not found when using type alias of enum  (Read 6284 times)

zamronypj

  • Full Member
  • ***
  • Posts: 133
    • Fano Framework, Free Pascal web application framework
If I have code

MyTypes.pas
Code: Pascal  [Select][+][-]
  1. unit MyTypes;
  2.  
  3. interface
  4.  
  5. type
  6.  
  7.     TMyType = (typeA, typeB);
  8.  
  9. implementation
  10.  
  11. end.

MyTypesAlias.pas
Code: Pascal  [Select][+][-]
  1. unit MyTypesAlias;
  2.  
  3. interface
  4.  
  5. uses
  6.  
  7.     MyTypes;
  8.  
  9. type
  10.  
  11.     TMyType = MyTypes.TMyType;
  12.  
  13. implementation
  14.  
  15. end.

testType.pas

Code: Pascal  [Select][+][-]
  1. program testType;
  2.  
  3. uses MyTypesAlias;
  4.  
  5. var
  6.  
  7.     ftype : TMyType;
  8.  
  9. begin
  10.     ftype := typeA;
  11. end.

Compilation of testType.pas failed with error 'Error: Identifier not found "typeA"'. Why?

I thought both MyTypes.TMyType and MyTypesAlias.TMyType are identical thus should be able to resolve typeA is coming from original type.
« Last Edit: June 19, 2021, 05:23:42 am by zamronypj »
Fano Framework, Free Pascal web application framework https://fanoframework.github.io
Apache module executes Pascal program like scripting language https://zamronypj.github.io/mod_pascal/
Github https://github.com/zamronypj

Kays

  • Hero Member
  • *****
  • Posts: 569
  • Whasup!?
    • KaiBurghardt.de
Re: Why identifier not found when using type alias of enum
« Reply #1 on: June 18, 2021, 07:33:15 pm »
Good question!
[…] Why? […]
Why? I’ll explain you why.

Code: Pascal  [Select][+][-]
  1.     TMyType = (typeA, typeB);
This line creates two symbols for every enumeration data type member.
  • TMyType.typeA (primary)
  • typeA (an alias, which can be turned off by using {$scopedEnums on})
You usually use the latter, the alias, because that’s how Pascal defines it (the concept of enumeration data types). Both symbols are in the unit scope, i. e. MyTypes.

Code: Pascal  [Select][+][-]
  1.     TMyType = MyTypes.TMyType;
Here, you actually want to write
Code: Pascal  [Select][+][-]
  1.     TMyType = TMyType;
which is, however, illegal, thus you needed to prefix the scope. While you can use the “unscoped” alias in MyTypeAlias, because the the unit scope MyTypes appears in the uses clause, you cannot do the same in TestType, because only MyTypeAlias is in the “routing table”. You know what I mean? You can still write
Code: Pascal  [Select][+][-]
  1.     ftype := TMyType.typeA;
but the FQI (fully-qualified identifier)
Code: Pascal  [Select][+][-]
  1.     ftype := MyTypes.TMyType.typeA;
does not work, because the unit MyTypes is unknown to TestType.

By the way, Extended Pascal defines a far more sophisticated mechanism in importing and exporting identifiers, yet the FPC does not support it (yet).
Yours Sincerely
Kai Burghardt

alpine

  • Hero Member
  • *****
  • Posts: 1032
Re: Why identifier not found when using type alias of enum
« Reply #2 on: June 18, 2021, 08:11:00 pm »
Why someone should expect a "transitive" visibility of an identifier defined in a compilation unit not directly included in a use clause? AFAIK, identifier visibility is clearly defined and doesn't possess such a transitivity.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Kays

  • Hero Member
  • *****
  • Posts: 569
  • Whasup!?
    • KaiBurghardt.de
Re: Why identifier not found when using type alias of enum
« Reply #3 on: June 18, 2021, 08:38:28 pm »
Why someone should expect a "transitive" visibility of an identifier defined in a compilation unit not directly included in a use clause? […]
Because this would significantly clean up uses-clauses:
Code: Pascal  [Select][+][-]
  1. unit baseUnit;
  2. interface
  3. type
  4.         foo = (abc, xyz);
  5. implementation
  6. end.
Code: Pascal  [Select][+][-]
  1. unit extendingUnit;
  2.  
  3. interface
  4. uses
  5.         baseUnit;
  6. procedure doSomething(const what: foo);
  7.  
  8. implementation
  9. procedure doSomething(const what: foo);
  10. begin
  11. end;
  12. end.
Code: Pascal  [Select][+][-]
  1. program superProgram(input, output, stdErr);
  2.  
  3. uses
  4.         { actually, I _only_ want to import }
  5.         { and use identifiers from this unit }
  6.         extendingUnit,
  7.         { but still I need to import the base }
  8.         baseUnit;
  9.  
  10. begin
  11.         doSomething(abc);
  12. end.
I actually don’t want to list baseUnit, because it’s implicitly already there since I am using extendingUnit, yet still I am forced to use baseUnit anyway. This will make it difficult if I later decided to use in extendingUnit an alternative baseUnit implementation providing the same (or more) capabilities.
In PXSC-Pascal you could actually write use global extendingUnit which activates transitive visibility.
Yours Sincerely
Kai Burghardt

zamronypj

  • Full Member
  • ***
  • Posts: 133
    • Fano Framework, Free Pascal web application framework
Re: Why identifier not found when using type alias of enum
« Reply #4 on: June 18, 2021, 11:50:11 pm »
@Kays Thank you.

When we make type alias of enumeration type, it looks like compiler turns on $SCOPEENUMS silently even though it does not.
Fano Framework, Free Pascal web application framework https://fanoframework.github.io
Apache module executes Pascal program like scripting language https://zamronypj.github.io/mod_pascal/
Github https://github.com/zamronypj

zamronypj

  • Full Member
  • ***
  • Posts: 133
    • Fano Framework, Free Pascal web application framework
Re: Why identifier not found when using type alias of enum
« Reply #5 on: June 18, 2021, 11:59:45 pm »
Why someone should expect a "transitive" visibility of an identifier defined in a compilation unit not directly included in a use clause? AFAIK, identifier visibility is clearly defined and doesn't possess such a transitivity.

Quoted from https://www.freepascal.org/docs-html/ref/refse19.html :
"This construction is often seen after some refactoring, when moving some declarations from unit A to unit B, to preserve backwards compatibility of the interface of unit A."

With enumeration type using $SCOPEENUMS off (default), this does not preserve backward compatibility.
Fano Framework, Free Pascal web application framework https://fanoframework.github.io
Apache module executes Pascal program like scripting language https://zamronypj.github.io/mod_pascal/
Github https://github.com/zamronypj

alpine

  • Hero Member
  • *****
  • Posts: 1032
Re: Why identifier not found when using type alias of enum
« Reply #6 on: June 19, 2021, 01:10:53 am »
*snip*
Quoted from https://www.freepascal.org/docs-html/ref/refse19.html :
"This construction is often seen after some refactoring, when moving some declarations from unit A to unit B, to preserve backwards compatibility of the interface of unit A."
I'm not sure what are you talking about. The chapter is about type aliases, not identifier visibility.

With enumeration type using $SCOPEENUMS off (default), this does not preserve backward compatibility.
Again, what do you mean? What compatibility? Your original post was "Why I can't use the single enumeration identifiers although I have used a unit which defines a type alias to the original enumeration type (which is in a separate unit, a third one).  The answer is simple and is given by Kays - you just didn't used the unit in which the particular identifier is defined.

$SCOPEENUMS is just whether you should qualify the identifier or not.

@Kays,
I have used words "transitive visibility" meaning something like "If I see the type A, then I (implicitly) should see the identifiers which are used to define it.". Apparently this is not the case with Pascal.

The case with Pascal-XSC (I'm hearing it today, for which I apologize) , the "use global" clause seems to work in a IMHO, bizarre way, putting objects in a most general context possible. May be I am missing something, I've just started to read the reference.
 
So far, I'm not seeing a relation between PXSC and the Extended Pascal as of ISO/IEC10206:1990, i.e. "use global" vs "import" semantics.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

zamronypj

  • Full Member
  • ***
  • Posts: 133
    • Fano Framework, Free Pascal web application framework
Re: Why identifier not found when using type alias of enum
« Reply #7 on: June 19, 2021, 05:17:54 am »
@y.ivanov what I means by backwards compatibility

Before refactor

Code: Pascal  [Select][+][-]
  1. Unit A;  
  2.  
  3. Interface  
  4.  
  5. Type  
  6.    TMyType = (myX, myY);
  7.  
  8. implementation
  9. end.
  10.  

Code: Pascal  [Select][+][-]
  1. program myprogram;
  2.  
  3. uses A;
  4.  
  5. var
  6.     ftype : TMyType;
  7. begin
  8.     ftype := myX;
  9. end.

myprogram.pas compiled successfully.

After refactor

Code: Pascal  [Select][+][-]
  1. Unit B;  
  2.  
  3. Interface  
  4.  
  5. Type  
  6.   MyType = (myX, myY);
  7.  
  8. implementation
  9. end.
  10.  

Code: Pascal  [Select][+][-]
  1. Unit A;  
  2.  
  3. Interface  
  4. uses B;
  5.  
  6. Type  
  7.     TMyType = B.TMyType;
  8.  
  9. implementation
  10. end.
  11.  

After refactor, myprogram.pas suddenly fails to compile so it does not backward compatible. you do not suffer such problem if type is for example ordinal type.
Fano Framework, Free Pascal web application framework https://fanoframework.github.io
Apache module executes Pascal program like scripting language https://zamronypj.github.io/mod_pascal/
Github https://github.com/zamronypj

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Why identifier not found when using type alias of enum
« Reply #8 on: June 19, 2021, 03:38:46 pm »
@Kays Thank you.

When we make type alias of enumeration type, it looks like compiler turns on $SCOPEENUMS silently even though it does not.

No, it does not. You only alias the type, but not the global enum entries. If you want to alias them as well you need to do this:

Code: Pascal  [Select][+][-]
  1. type
  2.   TMyType = B.TMyType;
  3.  
  4. const
  5.   myX = B.myX;
  6.   myY = B.myY;

The RTL uses this for the TypInfo unit, because the TTypeKind was moved from TypInfo to System (see here).

 

TinyPortal © 2005-2018