Recent

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

440bx

  • Hero Member
  • *****
  • Posts: 5182
Re: making types totally incompatible
« Reply #15 on: April 13, 2025, 07:25:10 am »
just for the record, the statements
Code: Pascal  [Select][+][-]
  1.   writeln('m1 = ', m1.Value:0:2);
  2.   writeln('km1 = ', km1.Value:0:2);
  3.  
can be replaced with
Code: Pascal  [Select][+][-]
  1.   writeln('m1 = ',  double(m1 ):0:2);
  2.   writeln('km1 = ', double(km1):0:2);
  3.  
which makes using the record's field name unnecessary BUT, it creates an undesirable type dependency because if the type is changed from double to something else the effect of typecasting may not yield expected behavior.

One way or another there is always something that is less than ideal.
(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: 16813
  • Ceterum censeo Trump esse delendam
Re: making types totally incompatible
« Reply #16 on: April 13, 2025, 08:25:17 am »
How do global properties help with unwanted assignment compatibility between distinct types?
RTTI:
Although for both types the type kind is tkInteger, the type names differ.
You can use that for e.g operators where you can test for type name to determine equivalence or you can write functions that do the same.

Actually, it is not necessary to do that with global properties. It will work directly.
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. uses typinfo;
  3.  
  4. type
  5.   TMy1 = type integer;
  6.   TMy2 = type integer;
  7.  
  8. var
  9.   a:TMy1 = 100;
  10.   b:TMy2 = 5;  
  11.   Info1, Info2:PTypeInfo;
  12. begin
  13.   Info1 := TypeInfo(a);
  14.   Info2 := TypeInfo(b);
  15.   writeln('Equal types?',Info1^.Name = Info2^.name);
  16. end.
« Last Edit: April 13, 2025, 08:40:50 am by Thaddy »
Changing servers. thaddy.com may be temporary unreachable but restored when the domain name transfer is done.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8378
Re: making types totally incompatible
« Reply #17 on: April 13, 2025, 09:36:18 am »
Just to keep the pot boiling.

Regrettably, all of the assignments etc. below work:

Code: Pascal  [Select][+][-]
  1. type
  2.   TMeters= type double;
  3.   TKilometers= type double;
  4.   TFeet= type integer;
  5. ...
  6.  
  7. procedure testTypeCompatibility;
  8.  
  9. const
  10.   meters: TMeters= 1.0;
  11.   kilometers: TKilometers= 1.0;
  12.  
  13. var
  14.   m: TMeters;
  15.   k: TKilometers;
  16.   d: double;
  17.  
  18.  
  19.   procedure pM(m: TMeters);
  20.  
  21.   begin
  22.   end { pM } ;
  23.  
  24.  
  25. begin
  26.   m := kilometers;                      (* Should fail                          *)
  27.   m := meters;                          (* Should be OK                         *)
  28.   k := meters;                          (* Should fail                          *)
  29.   k := kilometers;                      (* Should be OK                         *)
  30.   d := meters;                          (* Should fail                          *)
  31.   d := kilometers;                      (* Should fail                          *)
  32.   d := m;                               (* Should fail                          *)
  33.   m := d;                               (* Should fail                          *)
  34.   k := d;                               (* Should fail                          *)
  35.   pM(meters);                           (* Should be OK                         *)
  36.   pM(m);                                (* Should be OK                         *)
  37.   pM(kilometers);                       (* Should fail                          *)
  38.   pM(k);                                (* Should fail                          *)
  39.   pM(d)                                 (* Should fail                          *)
  40. end { testTypeCompatibility } ;
  41.  

If TMetres etc. were actually defined as records with a single field, could that field be set to be the default (i.e. accessed implicitly if not specified)?

...OTOH that probably wouldn't help because implicit access to the value (i.e. a double whatever) would hide the distinct type of the record :-(

I think I asked this elsewhere in the context of Delphi ten years or so ago, because I was musing about the capabilities of a C++ toolkit which could actually flag dimensionality errors (i.e. assigning seconds to meters etc.) as a compilation error. I was given a workaround, but it was subtle and might have relied on RTTI etc... not sure whether I can find it, and not sure whether it's worth the effort.

I could possibly justify heavy modification of the code to encode distances as a record including both a value and a datum, but that's not going to happen immediately. Tightening up all functions etc. to use a TMetres or TFeet rather than just a double or integer would be a good start.

I've not actually seen a screwed assignment, but this started when I realised that I was outputting something as feet when it was still actually in meters: which is of course a whole other can of worms.

MarkMLl
« Last Edit: April 13, 2025, 09:49:44 am by 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: 5182
Re: making types totally incompatible
« Reply #18 on: April 13, 2025, 10:59:13 am »
<snip> this started when I realised that I was outputting something as feet when it was still actually in meters: which is of course a whole other can of worms.
I seem to remember @Circular worked on a unit that created dimension types and protected against such mixups.  My recollection of it is very sketchy, I'll leave it to @Circular to provide more details if he happens to read this.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

paweld

  • Hero Member
  • *****
  • Posts: 1361
Best regards / Pozdrawiam
paweld

440bx

  • Hero Member
  • *****
  • Posts: 5182
Re: making types totally incompatible
« Reply #20 on: April 13, 2025, 11:51:34 am »
@paweld,

Thank you.  For some reason I couldn't find it.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8378
Re: making types totally incompatible
« Reply #21 on: April 13, 2025, 12:46:59 pm »
I think I asked this elsewhere in the context of Delphi ten years or so ago, because I was musing about the capabilities of a C++ toolkit which could actually flag dimensionality errors (i.e. assigning seconds to meters etc.) as a compilation error. I was given a workaround, but it was subtle and might have relied on RTTI etc... not sure whether I can find it, and not sure whether it's worth the effort.

I've been looking back through a private conferencing system's archive, and found this which I hope will amuse if nothing else:

Quote
> Will, do you remember the example you gave a few years ago of how (code written in) C++ could track the dimensions of quantities (i.e. mass-length-time dimensional analysis)?

Yes indeed. The modern, de facto standard version of that library is Boost's Units library:

http://www.boost.org/doc/libs/1_61_0/doc/html/boost_units.html

> Can C-hash [must fix this damn keyboard] do anything similar?

C++'s ability to do this is a consequence of its early, eccentric implementation of generics (small integer constants can be treated as types!), which can be [ab]used to perform meta-programming, ie application code that runs at compile time. This is how the library is implemented.

Later implementers of generics in other languages (Java, Delf and, I believe, C#) used a less mad approach which is easier all round, but lacks C++'s facility for interesting perversion.

Now that it has been shown that it can be put to useful purpose, C++ is gaining actually properly designed new features that should make it possible to do this thing using less bizarre mechanisms. Also, Walter Bright's D has support for this sort of thing by design.

As for C#, I await Matthew's pronouncement in due course. When's he's watched the appropriate PluralSight course ;-)

MarkMLl
« Last Edit: April 13, 2025, 02:22:20 pm by 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

Khrys

  • Full Member
  • ***
  • Posts: 215
Re: making types totally incompatible
« Reply #22 on: April 14, 2025, 08:14:10 am »
Quote
[...] eccentric implementation of generics [...]

This gives me an idea:

Code: Pascal  [Select][+][-]
  1. type
  2.   generic TQuantity<T, const Symbol: String> = record
  3.   private type
  4.     TSelf = specialize TQuantity<T, Symbol>;
  5.   private
  6.     Value: T;
  7.   public
  8.     class operator explicit(const Self: TSelf): T;
  9.     class operator explicit(const AValue: T): TSelf;
  10.     class operator +(const A, B: TSelf): TSelf;
  11.     // class operator - [...] etc.
  12.     function ToString(): String;
  13.   end;
  14.  
  15. class operator TQuantity.explicit(const Self: TSelf): T;
  16. begin
  17.   Result := Self.Value;
  18. end;
  19.  
  20. class operator TQuantity.explicit(const AValue: T): TSelf;
  21. begin
  22.   Result.Value := AValue;
  23. end;
  24.  
  25. class operator TQuantity.+(const A, B: TSelf): TSelf;
  26. begin
  27.   Result.Value := A.Value + B.Value;
  28. end;
  29.  
  30. function TQuantity.ToString(): String;
  31. begin
  32.   if TypeInfo(T) = TypeInfo(Double) then
  33.     Result := Format('%.2f %s', [PDouble(@Value)^, Symbol])
  34.   else if TypeInfo(T) = TypeInfo(Integer) then
  35.     Result := Format('%d %s', [PInteger(@Value)^, Symbol])
  36.   else
  37.     Result := '??? ' + Symbol;
  38. end;

With these changes...

Code: Pascal  [Select][+][-]
  1. type
  2.   TMeters= specialize TQuantity<Double, 'm'>;
  3.   TKilometers= specialize TQuantity<Double, 'km'>;
  4.   TFeet= specialize TQuantity<Integer, ''''>;
  5. ...
  6.  
  7. procedure testTypeCompatibility;
  8.  
  9. const
  10.   meters: TMeters= (Value: 1.0);
  11.   kilometers: TKilometers= (Value: 1.0);

...all the tests pass/fail as expected:

Code: Text  [Select][+][-]
  1. test.pas(26,8) Error: Incompatible types: got "TQuantity<System.Double,test.Constant String>" expected "TQuantity<System.Double,test.AnsiChar>"
  2. test.pas(28,8) Error: Incompatible types: got "TQuantity<System.Double,test.AnsiChar>" expected "TQuantity<System.Double,test.Constant String>"
  3. test.pas(30,8) Error: Incompatible types: got "TQuantity<System.Double,test.AnsiChar>" expected "Double"
  4. test.pas(31,8) Error: Incompatible types: got "TQuantity<System.Double,test.Constant String>" expected "Double"
  5. test.pas(32,8) Error: Incompatible types: got "TQuantity<System.Double,test.AnsiChar>" expected "Double"
  6. test.pas(33,8) Error: Incompatible types: got "Double" expected "TQuantity<System.Double,test.AnsiChar>"
  7. test.pas(34,8) Error: Incompatible types: got "Double" expected "TQuantity<System.Double,test.Constant String>"
  8. test.pas(37,16) Error: Incompatible type for arg no. 1: Got "TQuantity<System.Double,test.Constant String>", expected "TQuantity<System.Double,test.AnsiChar>"
  9. test.pas(38,7) Error: Incompatible type for arg no. 1: Got "TQuantity<System.Double,test.Constant String>", expected "TQuantity<System.Double,test.AnsiChar>"
  10. test.pas(39,7) Error: Incompatible type for arg no. 1: Got "Double", expected "TQuantity<System.Double,test.AnsiChar>"
« Last Edit: April 16, 2025, 07:35:29 am by Khrys »

Thaddy

  • Hero Member
  • *****
  • Posts: 16813
  • Ceterum censeo Trump esse delendam
Re: making types totally incompatible
« Reply #23 on: April 14, 2025, 08:54:51 am »
Neat!
Changing servers. thaddy.com may be temporary unreachable but restored when the domain name transfer is done.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8378
Re: making types totally incompatible
« Reply #24 on: April 14, 2025, 08:48:59 pm »
That's... interesting. I think I see what's going on, although I might end up using a simpler record-based system since I can justify storing a datum with each value.

What version of the compiler does that work with? It looks like trunk, including stuff that isn't documented yet.

If one used that to define types for meters, kilograms and seconds, I wonder how much of the MKS system would fall out without further intervention? :-)

For complicated reasons I did a batch of science O-levels (mid-teen public examinations) in a rush, and went into the physics exam knowing nothing but Ohm's law and dimensional analysis. Because we were supplied with a leaflet of constants showing what the dimensions of each were, I was able to work out everything else I needed on the fly :-)

MarkMLl

p.s. is that line 17 correct or should the RHS be Self rather than T?
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

TRon

  • Hero Member
  • *****
  • Posts: 4324
Re: making types totally incompatible
« Reply #25 on: April 14, 2025, 10:27:50 pm »
What version of the compiler does that work with? It looks like trunk, including stuff that isn't documented yet.
It requires trunk for the time being (it does not compile with 3.2.2), might have been back-ported to fixes (I did not checked).
Today is tomorrow's yesterday.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5940
  • Compiler Developer
Re: making types totally incompatible
« Reply #26 on: April 15, 2025, 10:31:33 pm »
What version of the compiler does that work with? It looks like trunk, including stuff that isn't documented yet.
It requires trunk for the time being (it does not compile with 3.2.2), might have been back-ported to fixes (I did not checked).

You probably mean constant generic parameters. These are only supported in main.

TRon

  • Hero Member
  • *****
  • Posts: 4324
Re: making types totally incompatible
« Reply #27 on: April 16, 2025, 03:14:41 am »
You probably mean constant generic parameters. These are only supported in main.
Thx, that is indeed the terminology I wasn't able to reproduce.

I'm also not sure if that is considered a new feature or correction on/for existing generics implementation (e.g. which release will eventually contain it, besides main that is).
Today is tomorrow's yesterday.

Khrys

  • Full Member
  • ***
  • Posts: 215
Re: making types totally incompatible
« Reply #28 on: April 16, 2025, 07:42:46 am »
p.s. is that line 17 correct or should the RHS be Self rather than T?

Whoops, you're right. Now it's correct  :-[
And yes, I tested this on trunk, although the constant generic parameter feature will turn 5 years old this month.

Thaddy

  • Hero Member
  • *****
  • Posts: 16813
  • Ceterum censeo Trump esse delendam
Re: making types totally incompatible
« Reply #29 on: April 16, 2025, 12:02:47 pm »
What version of the compiler does that work with? It looks like trunk, including stuff that isn't documented yet.
It may be documented when you build the documentation for main from source but I did not check that.
I only occasionally do that. Much, much less then I build main.
Building docs is easiest done, requires, Linux.
The docs are in a separate git repository.
Code: Bash  [Select][+][-]
  1. git clone cd <your fpc source directory> https://gitlab.com/freepascal.org/fpc/documentation.git documentation
  2. #required dependencies
  3. sudo apt-get install texlive-latex-base
  4. sudo apt-get install texlive-latex-extra
  5. sudo apt-get install texlive-latex-recommended
  6. sudo apt install pandoc #dunno of this is necessary
  7. cd documentation
  8. sudo make pdf
I think I left out something.. find out what.. edit later.

(I forgot building docs can take a long time on a slow computer, even on a fast computer.... silly me.)
« Last Edit: April 16, 2025, 01:11:42 pm by Thaddy »
Changing servers. thaddy.com may be temporary unreachable but restored when the domain name transfer is done.

 

TinyPortal © 2005-2018