Recent

Author Topic: making types totally incompatible  (Read 2277 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 8390
making types totally incompatible
« on: April 12, 2025, 08:14:03 pm »
How can one declare two types- for example doubles- so that they are never under any circumstances directly compatible?

Code: Pascal  [Select][+][-]
  1. type
  2.   TMetres: double;
  3.   TKilometres: double;
  4.  
  5. const
  6.   altitudeLimit: TMetres= 1500.0;
  7.   rangeLime: TKilometres= 20.0;
  8.  

They should not be assignment compatible, they should not be compatible as parameters (i.e. one is promoted to the other if a function taking it as parameter is undefined), and neither should be compatible with the base type (here, double, but the same might apply to integers).

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

jamie

  • Hero Member
  • *****
  • Posts: 6889
Re: making types totally incompatible
« Reply #1 on: April 12, 2025, 08:29:54 pm »
Make a proxy type of double?
The only true wisdom is knowing you know nothing

cdbc

  • Hero Member
  • *****
  • Posts: 2128
    • http://www.cdbc.dk
Re: making types totally incompatible
« Reply #2 on: April 12, 2025, 08:30:18 pm »
Hi Mark
I believe this is the way to do that:
Code: Pascal  [Select][+][-]
  1. type TMetres: double;
  2. type TKilometres: double;
It's got something to do with defining them in different 'type-blocks'  ...I think.
Seen it somewhere, long ago.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

440bx

  • Hero Member
  • *****
  • Posts: 5281
Re: making types totally incompatible
« Reply #3 on: April 12, 2025, 09:08:21 pm »
How can one declare two types- for example doubles- so that they are never under any circumstances directly compatible?

Code: Pascal  [Select][+][-]
  1. type
  2.   TMetres: double;
  3.   TKilometres: double;
  4.  
  5. const
  6.   altitudeLimit: TMetres= 1500.0;
  7.   rangeLime: TKilometres= 20.0;
  8.  

They should not be assignment compatible, they should not be compatible as parameters (i.e. one is promoted to the other if a function taking it as parameter is undefined), and neither should be compatible with the base type (here, double, but the same might apply to integers).

MarkMLl
I asked that question long ago.  I've been wanting to do that for ages.  There is no way to do it in a _convenient_ manner.

If you don't mind some inconvenience then it can be done like this:
Code: Pascal  [Select][+][-]
  1. type
  2.   ATrulyNewType = record
  3.     v               : double;
  4.   end;
  5.  
Unfortunately that means the value can only be accessed using <variable_name.v> which gets old quickly.  Since I tried this years ago, I remember that by typecasting ATrulyNewType to double you can sometimes dispense of having to qualify the variable name with the field.

What I also remember is that it was still quite inconvenient.  I abandoned every idea because none were simple and straightforward enough.

Supposedly but, it doesn't work, something like this is supposed(?) to work:
Code: Pascal  [Select][+][-]
  1.  
  2. type
  3.   TNew = type integer;
  4.  
but, TNew is still assignment compatible with integer which means it  is not really a new/different type.

Hopefully someone can provide a solution because I'd love to have it too.

I think it would be a really great feature if FPC gave some way of making the type definitions you showed _truly_ new and different types.  However, that means that assigning a value to it would require typecasting the value which is a small price to pay for a truly new type.

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

Thaddy

  • Hero Member
  • *****
  • Posts: 16939
  • Ceterum censeo Trump esse delendam
Re: making types totally incompatible
« Reply #4 on: April 12, 2025, 09:13:57 pm »
Supposedly but, it doesn't work, something like this is supposed(?) to work:
Code: Pascal  [Select][+][-]
  1.  
  2. type
  3.   TNew = type integer;
  4.  
but, TNew is still assignment compatible with integer which means it  is not really a new/different type.

That is indeed supposed to work, except.....for assignment ..(size)
It is a distinct type, though.
A possible way out: global properties, a feature not many people use or even know about:
https://www.freepascal.org/docs-html/3.2.0/ref/refse27.html#:~:text=A%20global%20block%20can%20declare%20properties%2C%20just%20as,a%20global%20property%20behaves%20like%20a%20class%20property.
« Last Edit: April 12, 2025, 09:21:00 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8390
Re: making types totally incompatible
« Reply #5 on: April 12, 2025, 09:25:57 pm »
I believe this is the way to do that:
Code: Pascal  [Select][+][-]
  1. type TMetres: double;
  2. type TKilometres: double;
It's got something to do with defining them in different 'type-blocks'  ...I think.
Seen it somewhere, long ago.

Ah- that's interesting, since it ties in with the special handling of records and pointers-to-records which again- AIUI and IIRC- have to be in the same block.

I think that will leave double compatible, but I'll check and report back tomorrow or Monday.

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

cdbc

  • Hero Member
  • *****
  • Posts: 2128
    • http://www.cdbc.dk
Re: making types totally incompatible
« Reply #6 on: April 12, 2025, 10:41:01 pm »
Sorry Mate, I checked...  They're assignment compatible even with:
Code: Pascal  [Select][+][-]
  1. type TMetres = type double;
  2. type TKilometres = type double;
Alas, could have been nice...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

Zoran

  • Hero Member
  • *****
  • Posts: 1948
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: making types totally incompatible
« Reply #7 on: April 12, 2025, 11:35:04 pm »
A possible way out: global properties, a feature not many people use or even know about:
https://www.freepascal.org/docs-html/3.2.0/ref/refse27.html#:~:text=A%20global%20block%20can%20declare%20properties%2C%20just%20as,a%20global%20property%20behaves%20like%20a%20class%20property.

How do global properties help with unwanted assignment compatibility between distinct types?
Swan, ZX Spectrum emulator https://github.com/zoran-vucenovic/swan

LV

  • Sr. Member
  • ****
  • Posts: 266
Re: making types totally incompatible
« Reply #8 on: April 12, 2025, 11:54:46 pm »
maybe something like that

Code: Pascal  [Select][+][-]
  1. {$Mode Delphi}       // Enable strict type checking
  2. {$ModeSwitch AdvancedRecords}
  3.  
  4. program project1;
  5.  
  6. type
  7.   // "Meters" type with controlled operations
  8.   TMetres = record
  9.   private
  10.     Value: Double; // Internal representation
  11.   public
  12.     // Allowed operations:
  13.     class operator Add(const A, B: TMetres): TMetres; // Addition of meters
  14.     class operator Implicit(const A: Double): TMetres; // Explicit conversion Double -> Metres
  15.   end;
  16.  
  17.   // "Kilometers" type with similar control
  18.   TKilometres = record
  19.   private
  20.     Value: Double;
  21.   public
  22.     class operator Add(const A, B: TKilometres): TKilometres;
  23.     class operator Implicit(const A: Double): TKilometres;
  24.   end;
  25.  
  26. { Implementation of operators for TMetres }
  27.  
  28. class operator TMetres.Add(const A, B: TMetres): TMetres;
  29. begin
  30.   Result.Value := A.Value + B.Value;
  31. end;
  32.  
  33. class operator TMetres.Implicit(const A: Double): TMetres;
  34. begin
  35.   Result.Value := A;
  36. end;
  37.  
  38. { Implementation of operators for TKilometres }
  39.  
  40. class operator TKilometres.Add(const A, B: TKilometres): TKilometres;
  41. begin
  42.   Result.Value := A.Value + B.Value;
  43. end;
  44.  
  45. class operator TKilometres.Implicit(const A: Double): TKilometres;
  46. begin
  47.   Result.Value := A;
  48. end;
  49.  
  50. var
  51.   m1, m2: TMetres;
  52.   km1, km2: TKilometres;
  53.   d: Double;
  54.  
  55. begin
  56.   // Examples of valid operations
  57.   m1 := 100.0;          // OK: implicit conversion via Implicit
  58.   m2 := 200.0;
  59.   m1 := m1 + m2;        // OK: addition of meters
  60.  
  61.   km1 := 5.0;           // OK
  62.   km2 := 10.0;
  63.   km1 := km1 + km2;     // OK: addition of kilometers
  64.  
  65.   // Examples of INVALID operations
  66.    m1 := m1 + km1;    // ERROR: Operator "+" not overloaded
  67.    km1 := km1 + m1;   // ERROR
  68.    d := m1;           // ERROR: Cannot assign "TMetres" to "Double"
  69.  
  70.   // Explicit conversion (only if logically justified)
  71.   m1 := TMetres(km1.Value * 1000); // Explicit casting
  72. end.
  73.  

440bx

  • Hero Member
  • *****
  • Posts: 5281
Re: making types totally incompatible
« Reply #9 on: April 13, 2025, 01:37:26 am »
maybe something like that

Code: Pascal  [Select][+][-]
  1. {$Mode Delphi}       // Enable strict type checking
  2. {$ModeSwitch AdvancedRecords}
  3.  
  4. ...
  5.  
  6. { etc }
  7.  
I have a question: why is the mode Delphi needed ?  what would be the difference with mode FPC or ObjFPC ?

Thank you in advance.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v4.0rc3) on Windows 7 SP1 64bit.

TRon

  • Hero Member
  • *****
  • Posts: 4359
Re: making types totally incompatible
« Reply #10 on: April 13, 2025, 01:50:12 am »
I have a question: why is the mode Delphi needed ?
Because it isn't. Probably something the poster is used to.

Note the differences in operator names between the modes in table 9.1 here.

Quote
what would be the difference with mode FPC or ObjFPC ?
I do believe mode objfpc (or delphi) is required for advanced records (methods and such).
« Last Edit: April 13, 2025, 02:06:06 am by TRon »
Today is tomorrow's yesterday.

440bx

  • Hero Member
  • *****
  • Posts: 5281
Re: making types totally incompatible
« Reply #11 on: April 13, 2025, 02:37:32 am »
@TRon,

If I understood what you said correctly, the only genuine difference resides in the different names used to identify operators unless mode Dellphi (which I never use) automatically enables advanced records too (don't really know if it does or not. )
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v4.0rc3) on Windows 7 SP1 64bit.

TRon

  • Hero Member
  • *****
  • Posts: 4359
Re: making types totally incompatible
« Reply #12 on: April 13, 2025, 02:44:39 am »
If I understood what you said correctly, the only genuine difference resides in the different names used to identify operators unless mode Dellphi (which I never use) automatically enables advanced records too (don't really know if it does or not. )
100% Affirmative. Mode delphi does indeed support advanced records out of the box.
Today is tomorrow's yesterday.

440bx

  • Hero Member
  • *****
  • Posts: 5281
Re: making types totally incompatible
« Reply #13 on: April 13, 2025, 03:45:33 am »
100% Affirmative. Mode delphi does indeed support advanced records out of the box.
Thank you.  That sets the record (pun!) straight :)
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v4.0rc3) on Windows 7 SP1 64bit.

LV

  • Sr. Member
  • ****
  • Posts: 266
Re: making types totally incompatible
« Reply #14 on: April 13, 2025, 07:01:27 am »
As an option for objfpc mode

Code: Pascal  [Select][+][-]
  1. {$mode objfpc} {$H+}
  2. {$ModeSwitch AdvancedRecords}
  3.  
  4. program project1;
  5.  
  6. type
  7.   // Type "Meters" with controlled operations
  8.   TMetres = record
  9.   private
  10.     Value: Double;
  11.   end;
  12.  
  13.   // Type "Kilometers" with similar control
  14.   TKilometres = record
  15.   private
  16.     Value: Double;
  17.   end;
  18.  
  19. // Operator overloads for TMetres
  20. operator + (const A, B: TMetres): TMetres;
  21. begin
  22.   Result.Value := A.Value + B.Value;
  23. end;
  24.  
  25. // Implicit conversion Double -> TMetres
  26. operator := (const A: Double): TMetres;
  27. begin
  28.   Result.Value := A;
  29. end;
  30.  
  31. // Operator overloads for TKilometres
  32. operator + (const A, B: TKilometres): TKilometres;
  33. begin
  34.   Result.Value := A.Value + B.Value;
  35. end;
  36.  
  37. // Implicit conversion Double -> TKilometres
  38. operator := (const A: Double): TKilometres;
  39. begin
  40.   Result.Value := A;
  41. end;
  42.  
  43. var
  44.   m1, m2: TMetres;
  45.   km1, km2: TKilometres;
  46.  
  47. begin
  48.   // Examples of valid operations
  49.   m1 := 100.0;    // Implicit conversion via operator :=
  50.   m2 := 200.0;
  51.   m1 := m1 + m2;  // Addition using overloaded +
  52.  
  53.   km1 := 5.0;
  54.   km2 := 10.0;
  55.   km1 := km1 + km2;
  56.  
  57.   // Output values via direct access to Value field
  58.   writeln('m1 = ', m1.Value:0:2);
  59.   writeln('km1 = ', km1.Value:0:2);
  60.  
  61.   // Examples of INVALID operations
  62.   // m1 := m1 + km1;  // Error: Incompatible types
  63.   // km1 := km1 + m1; // Error: Incompatible types
  64.  
  65.   readln;
  66. end.
  67.  

output:

Code: Text  [Select][+][-]
  1. m1 = 300.00
  2. km1 = 15.00
  3.  

 

TinyPortal © 2005-2018