Recent

Author Topic: Type alias/operator overload compiler bug or documentation error  (Read 5791 times)

russeld

  • New Member
  • *
  • Posts: 17
The free pascal documentation section on Type Aliases https://www.freepascal.org/docs-html/current/ref/refse19.html#x49-670003.8 discusses the case where the type keyword appears on the right hand side of a type definition:
Code: Pascal  [Select][+][-]
  1.    Type  
  2.       MyInteger = Type Integer;
  3.  
and goes on say that to from the point of view of the compiler these are different types, are assignment compatible and then lists the three consequences, the third one being:
Quote
They can be used in operator overloads, that is Operator +(A,B : MyInteger) : MyInteger;

In practice, this fails with "Error: impossible operator overload". Is this an error in the documentation or a compiler bug?

Although at first glance there seems to be no point in being able to overload the operators for assignment compatible types, it would be useful to do so for example to constrain the values a type can contain. For example:
Code: Pascal  [Select][+][-]
  1. type
  2.    qbit = type 0..$0F;   // In Delphi nybble=0..$F; qbit=type nybble; - more free pascal goodness :o)
  3.    TWrapInt = type -50 .. 50;
  4.    TConstrainedInt = type -5 .. 55;
  5.    
  6. operator := (Right: integer) Left: qbit;
  7. begin
  8.   Left := Right and $0F;    // <--- Unwanted recursion ?
  9. end;
  10.  
  11. operator := (Right: integer) Left: TWrapInt;
  12. begin
  13.    if Right > high(TWrapInt) then
  14.       Left := low(TWrapInt)       // <--- Unwanted recursion ?
  15.    else if Right < low(TWrapInt) then
  16.       Left := high(TWrapInt)    // <--- Unwanted recursion ?
  17.    else
  18.       Left := Right; // <--- Unwanted recursion ?
  19. end;
  20.      
  21. operator := (Right: integer) Left: TConstrainedInt;
  22. begin
  23.    if Right > high(TConstrainedInt) then
  24.       Left := high(TConstrainedInt)    // <--- Unwanted recursion ?
  25.    else if Right < low(TWrapInt) then
  26.       Left := low(TWrapInt)    // <--- Unwanted recursion ?
  27.    else
  28.       Left := Right; // <--- Unwanted recursion ?
  29. end;  
  30.  
  I realise that number of users who would want something like this is (very) limited, so I suppose the answer is that it is a documentation error :(

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Type alias/operator overload compiler bug or documentation error
« Reply #1 on: May 25, 2017, 10:22:24 am »
It may be a compiler error since the following compiles without error and works as expected:
Code: Pascal  [Select][+][-]
  1. type
  2.   TWrapInt = type -50..50;
  3.  
  4. function AssignTo(Right: Integer): TWrapInt;
  5. begin
  6.    if Right > High(TWrapInt) then
  7.      Exit(Low(TWrapInt))
  8.    else if Right < Low(TWrapInt) then
  9.      Exit(High(TWrapInt))
  10.    else
  11.      Exit(Right);
  12. end;

Thaddy

  • Hero Member
  • *****
  • Posts: 14214
  • Probably until I exterminate Putin.
Re: Type alias/operator overload compiler bug or documentation error
« Reply #2 on: May 25, 2017, 10:28:00 am »
It is simply the fact that the compiler has a resolution of byte, not nibble.
But there should be a way indeed to use operator overloads to perform operations on nibbles.
Nice puzzle and well spotted.
Specialize a type, not a var.

russeld

  • New Member
  • *
  • Posts: 17
Re: Type alias/operator overload compiler bug or documentation error
« Reply #3 on: May 25, 2017, 10:35:34 am »
It is simply the fact that the compiler has a resolution of byte, not nibble.
The sample given in the documentation:
Code: Pascal  [Select][+][-]
  1. type
  2.   MyInteger = type integer;
  3.  
  4. operator +(A, B : MyInteger): MyInteger;
  5. begin
  6.   result := A + B;
  7. end;    
  8.  
Also fails with the same error, so that can't be the reason
« Last Edit: May 25, 2017, 10:44:00 am by russeld »

russeld

  • New Member
  • *
  • Posts: 17
Re: Type alias/operator overload compiler bug or documentation error
« Reply #4 on: May 25, 2017, 11:03:16 am »
It may be a compiler error since the following compiles without error and works as expected:
I tried a second approach using records (yeugh), which compiles without errors, but it recurses until the stack overflows
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$ModeSwitch advancedrecords}
  3. type
  4.   qbit = record
  5.     class operator :=(A: Integer): qbit;
  6.     class operator :=(A: qbit): Integer;
  7.   end;
  8.  
  9. class operator qbit.:=(A: Integer): qbit;
  10. begin
  11.   exit(A and $0F); // Recursion occurs here
  12. end;
  13.  
  14. class operator qbit.:=(A: qbit): Integer;
  15. begin
  16.   exit(A); // And probably here as well
  17. end;
  18.  
  19. var
  20.   q1: qbit;
  21.   i: integer;
  22. begin
  23.   q1 := 19;
  24.   i := q1;
  25.   writeln(i);
  26.   readln;
  27. end.
So if there is some way to prevent recursion ....
« Last Edit: May 25, 2017, 11:06:11 am by russeld »

Thaddy

  • Hero Member
  • *****
  • Posts: 14214
  • Probably until I exterminate Putin.
Re: Type alias/operator overload compiler bug or documentation error
« Reply #5 on: May 25, 2017, 02:33:14 pm »
It is simply the fact that the compiler has a resolution of byte, not nibble.
The sample given in the documentation:
Code: Pascal  [Select][+][-]
  1. type
  2.   MyInteger = type integer;
  3.  
  4. operator +(A, B : MyInteger): MyInteger;
  5. begin
  6.   result := A + B;
  7. end;    
  8.  
Also fails with the same error, so that can't be the reason
You can not overload implicit operators. In the case of + for integers... Sorry, that won't work.
Specialize a type, not a var.

russeld

  • New Member
  • *
  • Posts: 17
Re: Type alias/operator overload compiler bug or documentation error
« Reply #6 on: May 25, 2017, 03:05:56 pm »
You can not overload implicit operators. In the case of + for integers... Sorry, that won't work.
I was simply using the example given in the documentation :)

Thaddy

  • Hero Member
  • *****
  • Posts: 14214
  • Probably until I exterminate Putin.
Re: Type alias/operator overload compiler bug or documentation error
« Reply #7 on: May 25, 2017, 06:51:07 pm »
Yup. you are right, that's a documentation bug since you can not override this since it is addition, subtraction etc for integer and these are compiler defined.
File a bug report against "documentation".
Specialize a type, not a var.

russeld

  • New Member
  • *
  • Posts: 17
Re: Type alias/operator overload compiler bug or documentation error
« Reply #8 on: June 04, 2017, 05:20:55 pm »
You can not overload implicit operators. In the case of + for integers... Sorry, that won't work.
Actually it does work, but only with the record type syntax:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$mode objfpc}{$H+}
  3. {$ModeSwitch advancedrecords}
  4. type
  5.   { nibble }
  6.   nibble = record
  7.     private
  8.       payload: integer;
  9.     public
  10.       class operator :=(Right: integer): nibble; inline;
  11.       class operator :=(Right: nibble): integer; inline;
  12.       // Other operators ...
  13.   end;
  14.  
  15. { nibble }
  16.  
  17. class operator nibble.:=(Right: integer): nibble;
  18. begin
  19.   result.payload := Right and $0F;
  20. end;
  21.  
  22. class operator nibble.:=(Right: nibble): integer;
  23. begin
  24.   result := Right.payload;
  25. end;
  26.  
  27. var
  28.   n: nibble;
  29.   b: byte;
  30.   i: integer;
  31. begin
  32.   n := $17;
  33.   writeln(integer(n));
  34.   b := $FF;
  35.   n := b;
  36.   i := n;
  37.   writeln(i);
  38.   readln;
  39. end.
  40.  

I didn't understand the record version syntax when I tried previously.

Because records cannot be forward declared, you can't define types which depend on each other as can be done in C#, for example conversion types tCelsius and tFahrenheit

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Type alias/operator overload compiler bug or documentation error
« Reply #9 on: June 04, 2017, 07:28:35 pm »
Because records cannot be forward declared, you can't define types which depend on each other as can be done in C#, for example conversion types tCelsius and tFahrenheit
Why not? C# uses garbage collection. We will replace it with the interface:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$MODE OBJFPC}
  4. {$APPTYPE CONSOLE}
  5.  
  6. type
  7.   IWithDegrees = interface(IInterface)
  8.     function GetDegrees: Single;
  9.     property Degrees: Single read GetDegrees;
  10.   end;
  11.  
  12.   TWithDegrees = class(TInterfacedObject, IWithDegrees)
  13.   private
  14.     FDegrees: Single;
  15.     function GetDegrees: Single;
  16.   public
  17.     constructor Create(const ADegrees: Single);
  18.   end;
  19.  
  20.   ICelsius = interface(IWithDegrees)
  21.   end;
  22.  
  23.   IFahrenheit = interface(IWithDegrees)
  24.   end;
  25.  
  26.   TCelsius = class(TWithDegrees, ICelsius)
  27.   end;
  28.  
  29.   TFahrenheit = class(TWithDegrees, IFahrenheit)
  30.   end;
  31.  
  32. operator := (const Celsius: ICelsius): IFahrenheit;
  33. begin
  34.   Result := TFahrenheit.Create(9.0/5.0 * Celsius.Degrees + 32);
  35. end;
  36.  
  37. operator := (const Fahrenheit: IFahrenheit): ICelsius;
  38. begin
  39.   Result := TCelsius.Create(5.0/9.0 * (Fahrenheit.Degrees - 32));
  40. end;
  41.  
  42. constructor TWithDegrees.Create(const ADegrees: Single);
  43. begin
  44.   inherited Create;
  45.   FDegrees := ADegrees;
  46. end;
  47.  
  48. function TWithDegrees.GetDegrees: Single;
  49. begin
  50.   Result := FDegrees;
  51. end;
  52.  
  53. var
  54.   Fahr, Fahr2: IFahrenheit;
  55.   c: ICelsius;
  56. begin
  57.   Fahr := TFahrenheit.Create(100.0);
  58.   Write(Fahr.Degrees:0:2, ' Fahrenheit');
  59.   c := Fahr;
  60.   Write(' = ', c.Degrees:0:2, ' Celsius');
  61.   Fahr2 := c;
  62.   Writeln(' = ', Fahr2.Degrees:0:2, ' Fahrenheit');
  63.   Readln;
  64. end.
« Last Edit: June 04, 2017, 07:34:37 pm by ASerge »

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Type alias/operator overload compiler bug or documentation error
« Reply #10 on: June 04, 2017, 09:59:52 pm »
@ASerge This is a simple and convincing example of the usefulness of COM interfaces. I think it deserves a place on a wiki page so it can be seen long after this thread is forgotten.

 

TinyPortal © 2005-2018