### Bookstore

 Computer Math and Games in Pascal Lazarus, the complete guide (only a few left)

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

#### russeld

• New member
• Posts: 11
##### Type alias/operator overload compiler bug or documentation error
« on: May 25, 2017, 10:00:11 am »
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: 2241
##### 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;

• Hero Member
• Posts: 4233
##### 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.
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

#### russeld

• New member
• Posts: 11
##### 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: 11
##### 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+}
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);
27. end.
So if there is some way to prevent recursion ....
« Last Edit: May 25, 2017, 11:06:11 am by russeld »

• Hero Member
• Posts: 4233
##### 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.
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

#### russeld

• New member
• Posts: 11
##### 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

• Hero Member
• Posts: 4233
##### 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".
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

#### russeld

• New member
• Posts: 11
##### 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+}
4. type
5.   { nibble }
6.   nibble = record
7.     private
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);
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

• Sr. Member
• Posts: 366
##### 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');
64. end.
« Last Edit: June 04, 2017, 07:34:37 pm by ASerge »

#### howardpc

• Hero Member
• Posts: 2241
##### 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.