Recent

Poll

I would like to see this feature added to the compiler

Yes
8 (34.8%)
No
10 (43.5%)
I don't care
5 (21.7%)

Total Members Voted: 23

Author Topic: Feature request: hard type creation/declaration  (Read 11769 times)

440bx

  • Hero Member
  • *****
  • Posts: 6556
Feature request: hard type creation/declaration
« on: July 07, 2025, 11:16:37 am »
Hello,

One of the possible problems when programming is passing a handle to the wrong thing to a function/procedure/method and the compiler is unable to catch this error because, as of now, most handles are assignment compatible with one another.

For instance, in Windows, an HWND can be assigned to an HMENU which can be assigned to an HPALETTE which can be assigned to an HBITMAP and so on.   This is because these types are not real types independent of each other but, synonyms of their underlying type (which is usually the same for most, if not all, handles.)

The request is simple: provide a way to declare types that even though may share the same underlying type are NOT assignment compatible with one another.  IOW, provide a simple and effective way to ensure an HWND cannot be assigned to an HBITMAP or anything else that is not an HWND (however, still allow typecasting.)

This would help prevent bugs and would set FPC apart.  It is a very, very simple feature but, it would really be a very nice feature to have.

I believe I have requested this feature in the past, I also believe I am not the only one to request it (using other words but, same concept.)  I believe the feature is important enough that it should be requested again.

Maybe if enough people support the addition of this feature, it might eventually make it into the compiler (of course, the sooner, the better.)

Comments welcome.

ETA:

Added poll
« Last Edit: July 07, 2025, 11:53:00 am by 440bx »
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12944
  • FPC developer.
Re: Feature request: hard type creation/declaration
« Reply #1 on: July 07, 2025, 11:24:56 am »
The syntax exist in pascal, but the Borland derived dialects lack in enforcing it.

Code: Pascal  [Select][+][-]
  1. Type
  2.    xx = type yyy;
  3.  

IIRC the description is something like "create a separate entry in the type symbol table for xx", in other words, "don't alias".

I'm no expert of the typesystem, but I assume it won't be a trivial {$modeswitch }, it will be harder to reconcile this with other typing related enhancements like the pointer type ( that is assignable from every pointer type), and ordinals, and overloads.

Personally I think this is a better avenue for a language improvement trajectory than the C operators and similar features that are mostly (shorthand) syntax only.

440bx

  • Hero Member
  • *****
  • Posts: 6556
Re: Feature request: hard type creation/declaration
« Reply #2 on: July 07, 2025, 11:45:28 am »
Code: Pascal  [Select][+][-]
  1. Type
  2.    xx = type yyy;
  3.  

IIRC the description is something like "create a separate entry in the type symbol table for xx", in other words, "don't alias".
I know what you mean.  The "type.... type" is _supposed_ to create a new type but, it doesn't.

As far as implementation, what comes to mind is for the compiler to consider the type as if it were defined as a record (internally it could be a record.)  That would automatically make it assignment incompatible with other types defined that way.  There would be one additional thing needed, those "records" should allow a short hand form of typecasting that would not be available with normal records, this because it would be a "field-less" record. 

That would allow assigning values of the underlying type, e.g, NEWTYPE = NEWTYPE(0);  which is something the compiler already does when assigning ordinal values to enumeration types.

Long story long already, I believe it might not take a lot of work to implement the feature because it could be mostly implemented using characteristics that are already part of the language and, the additional stuff seems to be isolated to when the type is declared.

Of course, implementation is something secondary.  First, there has to be agreement to adding the feature into the compiler.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 19388
  • Glad to be alive.
Re: Feature request: hard type creation/declaration
« Reply #3 on: July 07, 2025, 12:07:13 pm »
The type system is mainly to allow overloads.
An example:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2.  
  3. type
  4.   MyString = type AnsiString;
  5.  
  6.   procedure printme(const s:MyString);overload;
  7.   begin
  8.     write('Type system uses MyString: ');
  9.     writeln(s);
  10.   end;
  11.  
  12.   procedure printme(const s:AnsiString);overload;
  13.   begin
  14.     write('Type system uses AnsiString: ');
  15.     writeln(s);
  16.   end;
  17.  
  18. var
  19.   a:AnsiString = 'AnsiString';
  20.   b:MyString = 'MyString';
  21. begin
  22.   printme(a);
  23.   printme(b);
  24. end.
I believe this is documented somewhere.
Basically it does create a new type, but the types remain otherwise assignment compatible.
« Last Edit: July 07, 2025, 12:18:05 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8574
Re: Feature request: hard type creation/declaration
« Reply #4 on: July 07, 2025, 12:14:42 pm »
IIRC the description is something like "create a separate entry in the type symbol table for xx", in other words, "don't alias".
I know what you mean.  The "type.... type" is _supposed_ to create a new type but, it doesn't.

Xref to older thread https://forum.lazarus.freepascal.org/index.php/topic,70802.0.html

The upshot of that was that it should be possible to declare a hard type using a few dozen lines of generics, but this is at present only implemented in main.

I suggest that this be elevated to a request to get this into the compiler no later than 3.4

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

gidesa

  • Sr. Member
  • ****
  • Posts: 258
Re: Feature request: hard type creation/declaration
« Reply #5 on: July 07, 2025, 12:28:42 pm »
Hello,
 the topic was discussed in slightly different mode in
https://forum.lazarus.freepascal.org/index.php/topic,65981.
As of today, there is some usefulness of that syntax, although in very limited cases, described in FPC manual 3.8 paragraph.

Thaddy

  • Hero Member
  • *****
  • Posts: 19388
  • Glad to be alive.
Re: Feature request: hard type creation/declaration
« Reply #6 on: July 07, 2025, 12:49:45 pm »
Another example where the types are distinct:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc} {$H+}{$modeswitch typehelpers}
  2. type
  3.   Metres = type double;
  4.   Kilometres = type double;
  5. type  
  6.   TMetreHelper = type Helper for Metres
  7.   function ToKilometres:Kilometres;
  8.   end;
  9.  
  10.   TKiloMetreHelper = type helper for Kilometres
  11.   function ToMetres:Metres;
  12.   end;
  13.  
  14.   function TMetreHelper.ToKilometres:Kilometres;
  15.   begin
  16.     result := self / 1000;
  17.   end;
  18.  
  19.   function TKilometreHelper.ToMetres:Metres;
  20.   begin
  21.     result := self * 1000;
  22.   end;
  23.  
  24. var
  25.   m1: Metres = 500.0;
  26.   km1: Kilometres = 5.0;
  27. begin
  28.   writeln( km1 + m1.ToKilometres:4:2);
  29.   writeln( km1.ToMetres + m1:4:2);
  30.   readln;
  31. end.
The type helpers are strictly bound to the types: the type helper for metres is not accessible for kilometres and vice versa.
You don't need a record for that.
« Last Edit: July 07, 2025, 12:54:24 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8574
Re: Feature request: hard type creation/declaration
« Reply #7 on: July 07, 2025, 12:55:30 pm »
Another example where the types are distinct:
...
The type helpers are strictly bound to the types.

But when various people investigated this a few weeks ago it was found that underlying arithmetic wasn't, so even if helpers and overloads can be kept distinct there is a massive underlying trap for the unwary... and even for the wary.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 6556
Re: Feature request: hard type creation/declaration
« Reply #8 on: July 07, 2025, 01:02:21 pm »
Basically it does create a new type, but the types remain otherwise assignment compatible.
if it were a new type it wouldn't be assignment compatible, e.g, all records are new types and they are definitely not assignment compatible.



Currently there are convoluted ways to sort of implement new types but, they cause a lot of hassles.  They simply are not what a new type should be.



As I stated in the OP, I am aware that this is not the first time this feature has been suggested'/requested/discussed but, this is really a basic feature that should be implemented sooner rather than later (actually, it should already be implemented.)
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12517
  • Debugger - SynEdit - and more
    • wiki
Re: Feature request: hard type creation/declaration
« Reply #9 on: July 07, 2025, 02:01:20 pm »
Basically it does create a new type, but the types remain otherwise assignment compatible.
if it were a new type it wouldn't be assignment compatible, e.g, all records are new types and they are definitely not assignment compatible.

Exactly, so
Code: Pascal  [Select][+][-]
  1. type
  2.   HWND: record val: THandle; end;
  3.   HFont: record val: THandle; end;

Will do.

Of course, they are not assignment compatible, so any existing function declaration needs to be changed to use those types.

You can define operators for assignments you want to allow.

440bx

  • Hero Member
  • *****
  • Posts: 6556
Re: Feature request: hard type creation/declaration
« Reply #10 on: July 07, 2025, 02:49:17 pm »
That's probably the first thing anyone who has longed for hard types tries.  I tried to make it work to no avail, time wasted.

Using records to create hard types, does create hard types and in addition to that, a lot of hard headaches.  For instance, just try to assign a value to the type, e.g:
Code: Pascal  [Select][+][-]
  1.  
  2. type
  3.   TNEW = record v : ptruint; end;
  4.  
  5. var
  6.   SomeHandle : TNEW = TNEW(0);
  7.  
You can't typecast to the type.  To assign a value it is necessary to refer to the record field by name, that alone makes this "solution" completely inadequate as it depends on the name of a field.

That's just one of the _many_ problems you encounter when trying to use a hard type defined that way.  Simply stated, it does not work and the amount of hassle it creates isn't worth it.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 2071
Re: Feature request: hard type creation/declaration
« Reply #11 on: July 07, 2025, 03:56:57 pm »
I know what you mean.  The "type.... type" is _supposed_ to create a new type but, it doesn't.
Well it does so, just not for base types:
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyRec = record i: Integer end;
  3.  
  4.   TMyType = type TMyRec;
  5.   TOtherType = type TMyRec;
  6.  
  7. var
  8.   v1: TMyType;
  9.   v2: TOtherType;
  10. begin
  11.   v2:=v1; // Error
  12. end.

All base types are compatible with each other, which kindof makes sense because of ranges:
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyByte = 0..255;
  3.   TMyWord = 0..65535;
Those are also two different types, but they are compatible with each other. Basically any ordinal type is compatible with any other ordinal type as long as the ranges are comptible.
So when you write:
Code: Pascal  [Select][+][-]
  1. TMyType = type Byte;
It is exactly the same as if you write:
Code: Pascal  [Select][+][-]
  1. TMyType = 0..255;
And therefore is also compatible with other number types.

Basically in Pascal any number type is defined as a range, and any copy of such a type is also just a new definition using the same range. And range types have to be compatible with each other
« Last Edit: July 07, 2025, 03:59:08 pm by Warfley »

Thaddy

  • Hero Member
  • *****
  • Posts: 19388
  • Glad to be alive.
Re: Feature request: hard type creation/declaration
« Reply #12 on: July 07, 2025, 04:12:06 pm »
That is basically what I wrote, better formulated.
objects are fine constructs. You can even initialize them with constructors.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12517
  • Debugger - SynEdit - and more
    • wiki
Re: Feature request: hard type creation/declaration
« Reply #13 on: July 07, 2025, 04:45:26 pm »
That's probably the first thing anyone who has longed for hard types tries.  I tried to make it work to no avail, time wasted.

Using records to create hard types, does create hard types and in addition to that, a lot of hard headaches.  For instance, just try to assign a value to the type, e.g:
Code: Pascal  [Select][+][-]
  1.  
  2. type
  3.   TNEW = record v : ptruint; end;
  4.  
  5. var
  6.   SomeHandle : TNEW = TNEW(0);
  7.  
You can't typecast to the type.  To assign a value it is necessary to refer to the record field by name, that alone makes this "solution" completely inadequate as it depends on the name of a field.

That's just one of the _many_ problems you encounter when trying to use a hard type defined that way.  Simply stated, it does not work and the amount of hassle it creates isn't worth it.

You can, but its a bit more setup.

All the commented lines fail (currently testing with 331 / 323).
So:
- TFoo and TNew are incompatible.
- can be typecasted
- assignments of numbers can be done
-  "f:= TFoo(1);" also works / but I am not sure that it is a stable feature, it allows that even if TFoo has several fields...)
  --- EDIT: that works, because it calls the overloaded operator first, then casts the TFoo result of the operator to TFoo (which it already is)


Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$mode objfpc}
  3.  
  4.  
  5. type
  6.   TNEW = record v : ptruint; end;
  7.   TFoo = record v : ptruint; end;
  8.  
  9. operator := (a: integer): TNew;
  10. begin
  11.   result.v := a;
  12. end;
  13.  
  14. operator := (a: integer): TFoo;
  15. begin
  16.   result.v := a;
  17. end;
  18.  
  19. operator := (a: TNew): integer;
  20. begin
  21.   result := a.v;
  22. end;
  23.  
  24. operator := (a: TFoo): integer;
  25. begin
  26.   result := a.v;
  27. end;
  28.  
  29. procedure p(z: TNew); begin {} end;
  30.  
  31. var
  32.   n: TNew;
  33.   f: TFoo;
  34. begin
  35.   n:= 1;
  36.   p(n);
  37.   f:= TFoo(n);
  38.   //p(v);
  39.   //f:= n;
  40.   //n:=f;
  41.  
  42. end.
  43.  
« Last Edit: July 07, 2025, 05:00:51 pm by Martin_fr »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12517
  • Debugger - SynEdit - and more
    • wiki
Re: Feature request: hard type creation/declaration
« Reply #14 on: July 07, 2025, 04:49:53 pm »
Mind you, there may be a draw back for the optimizer.

Arguments to functions may not be passed in registers (not sure, maybe that is older fpc only).

Then again, simply don't use the record types in release builds. If you checked a debug/test build, and it compiled, then your types are ok. That doesn't change if your release doesn't use the records.



Mind:
- I did (try to) offer a solution that exists.
- I did not comment on the question of adding a dedicated language feature for this (that may or may not happen in FPC 4 or 5 or 6...).


 

TinyPortal © 2005-2018