Recent

Author Topic: how to cause the compiler to refuse a var declaration ?  (Read 4796 times)

440bx

  • Hero Member
  • *****
  • Posts: 3946
how to cause the compiler to refuse a var declaration ?
« on: January 09, 2022, 08:08:40 am »
Hello,

Consider the following simple program:
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2.  
  3. type
  4.   PTR_TO_OPAQUE_TYPE = ^TOPAQUE_TYPE;
  5.   TOPAQUE_TYPE       = record
  6.                          { record structure is opaque/unknown                 }
  7.                        end;
  8.  
  9. var
  10.   PtrToOpaqueType : PTR_TO_OPAQUE_TYPE;     { this is ok                      }
  11.  
  12.   VarToOpaqueType : TOPAQUE_TYPE;           { HOW TO MAKE THIS FAIL ?         }
  13.  
  14. begin
  15. end.

I would like the compiler to declare a fatal error when it sees the declaration of VarToOpaqueType (highlighted)

Is there some way to instruct the compiler to do that ?

Thank you for your help.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: how to cause the compiler to refuse a var declaration ?
« Reply #1 on: January 09, 2022, 12:05:03 pm »
I would like the compiler to declare a fatal error when it sees the declaration of VarToOpaqueType (highlighted)

Is there some way to instruct the compiler to do that ?

No, there is not.

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: how to cause the compiler to refuse a var declaration ?
« Reply #2 on: January 09, 2022, 12:28:11 pm »
but solution is easy.
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2.  
  3. type
  4.   PTR_TO_OPAQUE_TYPE = ^TOPAQUE_TYPE;
  5.   TOPAQUE_TYPE       = record
  6.                          { record structure is opaque/unknown                 }
  7.                        end;
  8.  
  9. var
  10.   PtrToOpaqueType : PTR_TO_OPAQUE_TYPE;     { this is ok                      }
  11.  
  12.   VarToOpaqueType : TOPAQUE_TYPE;           { HOW TO MAKE THIS FAIL ?         }
  13.  
  14. begin
  15.   // your code
  16.   {$if declared( VarToOpaqueType)}{$error 'VarToOpaqueType should fail'{$ifend} <<----
  17. end.
  18.  
You can put that to the end of your program..Just before end.
It will nicely fail at compile time
« Last Edit: January 09, 2022, 12:40:43 pm by Thaddy »
Specialize a type, not a var.

creaothceann

  • Full Member
  • ***
  • Posts: 117
Re: how to cause the compiler to refuse a var declaration ?
« Reply #3 on: January 09, 2022, 12:33:23 pm »
You could put the record type into its own unit, then add a check.

(Make sure that U_MyRecord doesn't appear in your *.lpr file.)

Code: [Select]
unit U_MyRecord;

interface

type
T_MyRecord = record
//...
end;

implementation

var
used : Boolean = False;

initialization
if used then Halt(1);
used := True;

end.

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: how to cause the compiler to refuse a var declaration ?
« Reply #4 on: January 09, 2022, 12:45:14 pm »
@440bx: Also note that the system unit already supports code like you wrote:
OpaqueData and POpaqueData. (I submitted that) from 3.2.0, maybe even as far back as 3.0.4 but not earlier.
https://www.freepascal.org/docs-html/rtl/system/popaquedata.html
« Last Edit: January 09, 2022, 12:51:32 pm by Thaddy »
Specialize a type, not a var.

balazsszekely

  • Guest
Re: how to cause the compiler to refuse a var declaration ?
« Reply #5 on: January 09, 2022, 12:47:03 pm »
I assuming that you wish to see a fatal error when the record is empty:
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2.  
  3. type
  4.   PTR_TO_OPAQUE_TYPE = ^TOPAQUE_TYPE;
  5.   TOPAQUE_TYPE       = record                        
  6.                          { record structure is opaque/unknown                 }
  7.                        end;
  8.  
  9. var
  10.   PtrToOpaqueType : PTR_TO_OPAQUE_TYPE;     { this is ok                      }
  11.  
  12.   VarToOpaqueType : TOPAQUE_TYPE;           { HOW TO MAKE THIS FAIL ?         }
  13.   {$if SizeOf(TOPAQUE_TYPE) = 0} {$error 'record is empty'}{$ifend}
  14.  
  15. begin
  16. end.

If you add something to the record the error is gone.

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: how to cause the compiler to refuse a var declaration ?
« Reply #6 on: January 09, 2022, 12:49:54 pm »
No, unless I misunderstood, he wants the declaration to fail. That can be done with my code. But as I wrote, his example code is more or less a duplicate from what's already in system.

The main reason for those two are to interface with external code and where you do not access or change that record yourself, but must be able to pass it back to some other routine  in the external code.
This is often the case with external API's

Maybe 440bx can confirm or deny my understanding?
Code: Pascal  [Select][+][-]
  1. {$IFDEF WINDOWS}{$APPTYPE CONSOLE}{$ENDIF}
  2.  var
  3.   PtrToOpaqueType : POpaqueData;     { this is ok                      }
  4.   VarToOpaqueType : TOpaqueData;     { HOW TO MAKE THIS FAIL ?         }
  5. begin
  6.   // your code
  7.   {$if declared( VarToOpaqueType)}{$error 'VarToOpaqueType should fail'}{$ifend}
  8. end.
I took the liberty to remove your types and change your declarations to the ones in system  :D 8-)
Note that if you put it at the end of your program it also catches any declaration(s) in the used units.
« Last Edit: January 09, 2022, 01:07:18 pm by Thaddy »
Specialize a type, not a var.

Zoran

  • Hero Member
  • *****
  • Posts: 1829
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: how to cause the compiler to refuse a var declaration ?
« Reply #7 on: January 09, 2022, 01:05:30 pm »
Thaddy, what you showed will only forbid declaring a variable named "VarOpaqueType".

I believe that what is actually asked for is to prohibit declaring any variable of that type, anywhere in programme.

The best I can think of is, create a separate unit only for that and:
Code: Pascal  [Select][+][-]
  1. unit UnitSomeTypes;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   SysUtils;
  9.  
  10. type
  11.   TSomeTypes = class sealed (TObject)
  12.   private
  13.     // hide these in private section, not to be seen from other units
  14.     type                                  
  15.       PTR_TO_OPAQUE_TYPE = ^TOPAQUE_TYPE;
  16.       TOPAQUE_TYPE = record
  17.       end;
  18.   public
  19.     class function newinstance: tobject; override;
  20.   end;
  21.  
  22.   // this can be seen in other units
  23.   PTR_TO_OPAQUE_TYPE = TSomeTypes.PTR_TO_OPAQUE_TYPE;
  24.  
  25. implementation
  26.  
  27. { TSomeTypes }
  28.  
  29. class function TSomeTypes.newinstance: tobject;
  30. begin
  31.   Result := nil;
  32.   raise Exception.Create('Do not try to instantiate this class!');
  33. end;
  34.  
  35. end.
  36.  

and then in the main program, you can use:
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   UnitSomeTypes;
  7.  
  8. type
  9.   PTR_TO_OPAQUE_TYPE = UnitSomeTypes.PTR_TO_OPAQUE_TYPE;
  10.  
  11. var
  12.   PtrToOpaqueType: PTR_TO_OPAQUE_TYPE;
  13.  
  14. begin
  15. end.
  16.  



Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: how to cause the compiler to refuse a var declaration ?
« Reply #8 on: January 09, 2022, 01:09:34 pm »
No. as I wrote:
when you put my line at the end of your program, just before end, it also covers all used units.
The program will not compile if the declaration appears anywhere in the total code.

I have editted my previous posts to make it more clear.

There is a slight drawback, though: it does not show you where that failed declaration comes from, so you need to grep the project to find it.
« Last Edit: January 09, 2022, 01:16:25 pm by Thaddy »
Specialize a type, not a var.

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: how to cause the compiler to refuse a var declaration ?
« Reply #9 on: January 09, 2022, 01:17:59 pm »
I assuming that you wish to see a fatal error when the record is empty:
The empty record is just a placeholder.  Its existence is valid but, declaring variables of that type is not valid.

That's why I was hoping that the compiler would provide something that would generate a compiler error if that empty record type is used to declare any variable.  Part of the reason is because it's empty but, it would still be an invalid declaration if I added some fields in there because, its layout isn't documented/known. 

IOW, using that empty record type should be considered an error. 

The only thing that comes to mind is simply to remove the empty record declaration.  That ensures a variable of that type cannot be declared since the type would no longer exist.  That's probably what I'll do and make it visible only after I've figured out at least the size of the record.

Everyone, thank you for all the suggestions and thank you @PascalDragon for a unambiguous answer even if it wasn't what I wanted to read.

@Zoran,

Interesting idea.  Unfortunately I cannot use it. 

I initially thought that a simple example of what I wanted to accomplish would be enough.  The reason I want to have that "unusable" type is because the Windows API Thread Pool functions use opaque types and all the functions take pointers to those opaque types.  I wanted to declare the record as initially empty but eventually add fields in there to figure out what the actual layout of that undocumented data structure is.  In the meantime, I don't want to inadvertently declare a variable of that type while it's empty.

Since the type is used by Windows APIs, it cannot be a class (that would change the semantics of the affected API definitions.)






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

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: how to cause the compiler to refuse a var declaration ?
« Reply #10 on: January 09, 2022, 01:31:28 pm »
The empty record is just a placeholder.  Its existence is valid but, declaring variables of that type is not valid.

That's why I was hoping that the compiler would provide something that would generate a compiler error if that empty record type is used to declare any variable.
Exactly. It is a placeholder. Hence TOpaqueData. Also the reason I submitted it.
And I hope I demonstrated that the compiler actually supports it if you instruct it to do so.
My define generates a compiler error if it is declared, You can also use Defined,but where it goes wrong is that you then have to define PTR_TO_OPAQUE_TYPE as a raw pointer.
That does not hurt and you can prevent use of the type by:
  {$if defined(TOPAQUE_TYPE)}{$error 'TOPAQUE_TYPE should fail'}{$ifend}
« Last Edit: January 09, 2022, 01:45:39 pm by Thaddy »
Specialize a type, not a var.

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: how to cause the compiler to refuse a var declaration ?
« Reply #11 on: January 09, 2022, 01:35:03 pm »
My define generates a compiler error if it is declared,
Yes but, the goal is to generate a compile error if the opaque/empty data type is used, not a specific variable of that type.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: how to cause the compiler to refuse a var declaration ?
« Reply #12 on: January 09, 2022, 01:46:32 pm »
Posts crossed.
See my last post, using defined. Is that acceptible?
Code: Pascal  [Select][+][-]
  1. {$IFDEF WINDOwS}{$APPTYPE CONSOLE}{$ENDIF}
  2. type
  3.   PTR_TO_OPAQUE_TYPE = type pointer;
  4. var
  5.   PtrToOpaqueType : PTR_TO_OPAQUE_TYPE;     { this is ok                      }
  6. begin
  7. end.
so we still can do type checking w/o pointer confusion
« Last Edit: January 09, 2022, 02:02:18 pm by Thaddy »
Specialize a type, not a var.

balazsszekely

  • Guest
Re: how to cause the compiler to refuse a var declaration ?
« Reply #13 on: January 09, 2022, 02:01:21 pm »
@440bx
Quote
The empty record is just a placeholder.  Its existence is valid but, declaring variables of that type is not valid.

That's why I was hoping that the compiler would provide something that would generate a compiler error if that empty record type is used to declare any variable.  Part of the reason is because it's empty but, it would still be an invalid declaration if I added some fields in there because, its layout isn't documented/known.

IOW, using that empty record type should be considered an error. 

Thanks for the detailed explanation. In my opinion the following code should fix the issue:
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2.  
  3. type
  4.   PTR_TO_OPAQUE_TYPE = ^TOPAQUE_TYPE;
  5.   TOPAQUE_TYPE       = record
  6.                          { record structure is opaque/unknown                 }
  7.                        end;
  8.  
  9. var
  10.   PtrToOpaqueType : PTR_TO_OPAQUE_TYPE;     { this is ok                      }
  11.  
  12.   VarToOpaqueType : TOPAQUE_TYPE;           { HOW TO MAKE THIS FAIL ?         }
  13.   {$if (Declared(VarToOpaqueType)) and (SizeOf(TOPAQUE_TYPE) = 0)} {$error 'record structure is opaque/unknown'}{$ifend}
  14.  
  15. begin
  16. end.

Record structure can be empty, but you cannot declare VarToOpaqueType until something is added to the record.

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: how to cause the compiler to refuse a var declaration ?
« Reply #14 on: January 09, 2022, 02:03:44 pm »
I still think  PTR_TO_OPAQUE_TYPE = type pointer; is the (a) solution.
This may have been an oversight when I submitted the request,
The above should do in most cases, since it is also a distinct type.
« Last Edit: January 09, 2022, 02:31:26 pm by Thaddy »
Specialize a type, not a var.

 

TinyPortal © 2005-2018