Type alias/operator overload compiler bug or documentation error lazarus / 64-FPC development ---------------------------------------------------------------------- russeld · 2017-05-25 08:00 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i    Type      MyInteger = Type Integer; 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: QuoteThey 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type   qbit = type 0..$0F;   // In Delphi nybble=0..$F; qbit=type nybble; - more free pascal goodness :o)   TWrapInt = type -50 .. 50;   TConstrainedInt = type -5 .. 55;   operator := (Right: integer) Left: qbit;begin  Left := Right and $0F;    // <--- Unwanted recursion ?end; operator := (Right: integer) Left: TWrapInt;begin   if Right > high(TWrapInt) then      Left := low(TWrapInt)       // <--- Unwanted recursion ?   else if Right < low(TWrapInt) then      Left := high(TWrapInt)    // <--- Unwanted recursion ?   else      Left := Right; // <--- Unwanted recursion ?end;      operator := (Right: integer) Left: TConstrainedInt;begin   if Right > high(TConstrainedInt) then      Left := high(TConstrainedInt)    // <--- Unwanted recursion ?   else if Right < low(TWrapInt) then      Left := low(TWrapInt)    // <--- Unwanted recursion ?   else      Left := Right; // <--- Unwanted recursion ?end;      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 · 2017-05-25 08:22 It may be a compiler error since the following compiles without error and works as expected: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  TWrapInt = type -50..50; function AssignTo(Right: Integer): TWrapInt;begin   if Right > High(TWrapInt) then     Exit(Low(TWrapInt))   else if Right < Low(TWrapInt) then     Exit(High(TWrapInt))   else     Exit(Right);end; ---------------------------------------------------------------------- Thaddy · 2017-05-25 08:28 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. ---------------------------------------------------------------------- russeld · 2017-05-25 08:35 Quote from: Thaddy on May 25, 2017, 10:28:00 amIt is simply the fact that the compiler has a resolution of byte, not nibble. The sample given in the documentation: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  MyInteger = type integer; operator +(A, B : MyInteger): MyInteger;begin  result := A + B;end;     Also fails with the same error, so that can't be the reason ---------------------------------------------------------------------- russeld · 2017-05-25 09:03 Quote from: howardpc on May 25, 2017, 10:22:24 amIt 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {$mode objfpc}{$H+}{$ModeSwitch advancedrecords}type  qbit = record    class operator :=(A: Integer): qbit;    class operator :=(A: qbit): Integer;  end; class operator qbit.:=(A: Integer): qbit;begin  exit(A and $0F); // Recursion occurs hereend; class operator qbit.:=(A: qbit): Integer;begin  exit(A); // And probably here as wellend; var  q1: qbit;  i: integer;begin  q1 := 19;  i := q1;  writeln(i);  readln;end. So if there is some way to prevent recursion .... ---------------------------------------------------------------------- Thaddy · 2017-05-25 12:33 Quote from: russeld on May 25, 2017, 10:35:34 amQuote from: Thaddy on May 25, 2017, 10:28:00 amIt is simply the fact that the compiler has a resolution of byte, not nibble. The sample given in the documentation: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type  MyInteger = type integer; operator +(A, B : MyInteger): MyInteger;begin  result := A + B;end;     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. ---------------------------------------------------------------------- russeld · 2017-05-25 13:05 Quote from: Thaddy on May 25, 2017, 10:28:00 amYou 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 · 2017-05-25 16:51 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". ---------------------------------------------------------------------- russeld · 2017-06-04 15:20 Quote from: Thaddy on May 25, 2017, 02:33:14 pmYou 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program Project1;{$mode objfpc}{$H+}{$ModeSwitch advancedrecords}type  { nibble }  nibble = record    private      payload: integer;    public      class operator :=(Right: integer): nibble; inline;      class operator :=(Right: nibble): integer; inline;      // Other operators ...  end; { nibble } class operator nibble.:=(Right: integer): nibble;begin  result.payload := Right and $0F;end; class operator nibble.:=(Right: nibble): integer;begin  result := Right.payload;end; var  n: nibble;  b: byte;  i: integer;begin  n := $17;  writeln(integer(n));  b := $FF;  n := b;  i := n;  writeln(i);  readln;end.  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 · 2017-06-04 17:28 Quote from: russeld on June 04, 2017, 05:20:55 pmBecause 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program Project1; {$MODE OBJFPC}{$APPTYPE CONSOLE} type  IWithDegrees = interface(IInterface)    function GetDegrees: Single;    property Degrees: Single read GetDegrees;  end;   TWithDegrees = class(TInterfacedObject, IWithDegrees)  private    FDegrees: Single;  function GetDegrees: Single;  public    constructor Create(const ADegrees: Single);  end;   ICelsius = interface(IWithDegrees)  end;   IFahrenheit = interface(IWithDegrees)  end;   TCelsius = class(TWithDegrees, ICelsius)  end;   TFahrenheit = class(TWithDegrees, IFahrenheit)  end; operator := (const Celsius: ICelsius): IFahrenheit;begin  Result := TFahrenheit.Create(9.0/5.0 * Celsius.Degrees + 32);end; operator := (const Fahrenheit: IFahrenheit): ICelsius;begin  Result := TCelsius.Create(5.0/9.0 * (Fahrenheit.Degrees - 32));end; constructor TWithDegrees.Create(const ADegrees: Single);begin  inherited Create;  FDegrees := ADegrees;end; function TWithDegrees.GetDegrees: Single;begin  Result := FDegrees;end; var  Fahr, Fahr2: IFahrenheit;  c: ICelsius;begin  Fahr := TFahrenheit.Create(100.0);  Write(Fahr.Degrees:0:2, ' Fahrenheit');  c := Fahr;  Write(' = ', c.Degrees:0:2, ' Celsius');  Fahr2 := c;  Writeln(' = ', Fahr2.Degrees:0:2, ' Fahrenheit');  Readln;end. ---------------------------------------------------------------------- howardpc · 2017-06-04 19:59 @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.