* * *

Author Topic: Simple type helper method fail on Lazarus 64-bit  (Read 716 times)

furious programming

  • Jr. Member
  • **
  • Posts: 68
  • I click a little.
    • TreeStructInfo - format for text and binary configuration files
Simple type helper method fail on Lazarus 64-bit
« on: September 13, 2018, 08:12:21 pm »
Custom helpers short test, for simple type like Integer:

Code: Pascal  [Select]
  1. program main;
  2.  
  3. {$MODE OBJFPC}{$LONGSTRINGS ON}{$MODESWITCH TYPEHELPERS}{$INLINE ON}
  4.  
  5. uses
  6.   SysUtils;
  7.  
  8. type
  9.   TIntegerHelper = type helper(SysUtils.TIntegerHelper) for Integer
  10.   public
  11.     function Divisible(ADivider: Integer): Boolean; inline;
  12.   end;
  13.  
  14.   function TIntegerHelper.Divisible(ADivider: Integer): Boolean;
  15.   begin
  16.     Result := Self mod ADivider = 0;
  17.   end;
  18.  
  19. var
  20.   Number: Integer = 20;
  21. begin
  22.   WriteLn('Variable:   ', Number.Divisible(10));
  23.   WriteLn('Expression: ', (Number + 5).Divisible(10));
  24. end.

On Lazarus 1.8.4 32-bit (with FPC 3.0.4) the project can be compiled and works properly. The output is:

Code: Pascal  [Select]
  1. Variable:   TRUE
  2. Expression: FALSE

No surprises. On stable Lazarus 1.8.4 but 64-bit, I got compile time error:

Code: Pascal  [Select]
  1. WriteLn('Expression: ', (Number + 5).Divisible(10));
  2. //                                   ^
  3. //                                   Error: Illegal qualifier

Why? Why I can use methods in both ways on 32-bit and cannot do the same on 64-bit?
« Last Edit: September 13, 2018, 08:23:34 pm by furious programming »

howardpc

  • Hero Member
  • *****
  • Posts: 2751
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #1 on: September 13, 2018, 09:29:05 pm »
Why? Why I can use methods in both ways on 32-bit and cannot do the same on 64-bit?
For some reason the 64-bit  Expression version requires a cast to keep the compiler happy
Code: Pascal  [Select]
  1. WriteLn('Expression: ', Integer(Number2 + 5).Divisible(10));

furious programming

  • Jr. Member
  • **
  • Posts: 68
  • I click a little.
    • TreeStructInfo - format for text and binary configuration files
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #2 on: September 13, 2018, 09:34:09 pm »
Indeed. But I am just interested in this "some reason"—bug or feature?
« Last Edit: September 13, 2018, 09:37:56 pm by furious programming »

lucamar

  • Full Member
  • ***
  • Posts: 193
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #3 on: September 13, 2018, 10:47:27 pm »
Just a wild guess and probably not true but, can it be that the expression resolves to a type other than Integer in 64bit? Although it should be the same in all platforms, shouldn't it?
Been there, done that ... barely kept the timelines.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 1.8.4/fpc 3.0.4 - Ubuntu 10, Kubuntu 14, Windows XP SP3 (Home & Prof.) and various DOS incarnations.

howardpc

  • Hero Member
  • *****
  • Posts: 2751
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #4 on: September 13, 2018, 11:07:42 pm »
On 64-bit platforms the expression may be Int64 internally? The typehelper is specific for longint.

jamie

  • Hero Member
  • *****
  • Posts: 809
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #5 on: September 13, 2018, 11:49:59 pm »
Welcome to bug city....

 This is an old bug I reported long ago, its not limited to just this of course, it also effects doing
math within the parameter passing to a function, it magically converts the result type to the highest..

 WORDTYPE+1 = an integertype+1 now...

  for 32 bit the integer is the full bus size which is 32 bit which is also the integer..

  in 64 bit mode, its a 64 bit but the integers are still considered 32 bit, it just uses the
lower half..

 If you do that math outside..

 SomeWordVariable := SomeWordVariable +1;  still is a WordVariable…

 yes, casting is the cure but, kind of sloppy in a helper...


 This problem also causes issues with overloading functions, you do some math within the
parameter passing and it may picked the wrong function or complain there isn't any matching
function, or can't decide on which one to use..

furious programming

  • Jr. Member
  • **
  • Posts: 68
  • I click a little.
    • TreeStructInfo - format for text and binary configuration files
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #6 on: September 14, 2018, 12:43:09 am »
On 64-bit platforms the expression may be Int64 internally? The typehelper is specific for longint.

Hmm… the documentation says something else:

Quote from: Integer
Currently, the integer type is only dependent on $mode, not on the CPU type. An integer is 16-bit in TP or FPC modes, or 32-bit in ObjFPC or Delphi modes.

I'm using ObjFPC always, so the Integer type should be 32-bit wide, but apparently it is not.

ASerge

  • Hero Member
  • *****
  • Posts: 900
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #7 on: September 14, 2018, 04:05:35 am »
FPC 3.04 64-bit output "Int64 2":
Code: Pascal  [Select]
  1. {$APPTYPE CONSOLE}
  2. {$MODE OBJFPC}
  3.  
  4. procedure Test(N: Int64);
  5. begin
  6.   Writeln('Int64 ', N);
  7. end;
  8.  
  9. procedure Test(N: Integer);
  10. begin
  11.   Writeln('Integer ', N);
  12. end;
  13.  
  14. var
  15.   N: Integer = 1;
  16. begin
  17.   Test(N + 1);
  18.   Readln;
  19. end.

Thaddy

  • Hero Member
  • *****
  • Posts: 6730
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #8 on: September 14, 2018, 08:05:30 am »
The documentation is here: https://www.freepascal.org/docs-html/current/ref/refsu4.html
The wiki is out-of-sync and as usual unreliable or at least incomplete.

Note the remark about the difference with Delphi in the real documentation.

I wish people referring to "the documentation" would first refer to the real documentation: the manuals. And not the wiki.
The manuals are rather better maintained than the wiki and can be subject to mantis bug reports as opposed to the wiki, which is an anarchic free for all.
Documentation bugs are usually fixed very quickly.

But given the real documentation I consider this a bug: the typecast should not be necessary since integer is strictly typed to either 2 or 4 bytes.
« Last Edit: September 14, 2018, 08:11:25 am by Thaddy »
Ada's daddy wrote this:"Fools are my theme, let satire be my song."

howardpc

  • Hero Member
  • *****
  • Posts: 2751
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #9 on: September 14, 2018, 08:49:44 am »
On 64-bit platforms the expression may be Int64 internally? The typehelper is specific for longint.

Hmm… the documentation says something else:

Quote from: Integer
Currently, the integer type is only dependent on $mode, not on the CPU type. An integer is 16-bit in TP or FPC modes, or 32-bit in ObjFPC or Delphi modes.

I'm using ObjFPC always, so the Integer type should be 32-bit wide, but apparently it is not.
The issue is not the size of the integer type, but the size of the expression, the result of two integers being added. This was the point of "internally" in my comment.
You declare Number to be a longint, which means it could take the value High(longint). So the expression (Number + 5) would overflow in that case, unless the compiler internally provides an Int64 variable for the result.
So this seems to me not a bug, but an expected strategy for avoiding avoidable overflow errors.



Thaddy

  • Hero Member
  • *****
  • Posts: 6730
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #10 on: September 14, 2018, 11:03:07 am »
Indeed. If a similar helper for int64 is defined, then that one is chosen and the cast is not necessary.
Code: Pascal  [Select]
  1. program main;
  2.  
  3. {$MODE OBJFPC}{$LONGSTRINGS ON}{$MODESWITCH TYPEHELPERS}{$INLINE ON}
  4.  
  5. uses
  6.   SysUtils;
  7.  
  8. type
  9.   TIntegerHelper = type helper(SysUtils.TIntegerHelper) for Integer
  10.   public
  11.     function Divisible(ADivider: Integer): Boolean; inline;
  12.   end;
  13.  
  14.   TInt64Helper = type helper(SysUtils.TInt64Helper) for Int64
  15.   public
  16.     function Divisible(ADivider: Int64): Boolean; inline;
  17.   end;
  18.  
  19.   function TIntegerHelper.Divisible(ADivider: Integer): Boolean;
  20.   begin
  21.     Result := Self mod ADivider = 0;
  22.   end;
  23.  
  24.   function TInt64Helper.Divisible(ADivider: Int64): Boolean;
  25.   begin
  26.     Result := Self mod ADivider = 0;
  27.   end;
  28.  
  29. var
  30.   Number: Integer = 20;
  31. begin
  32.   WriteLn('Variable:   ', Number.Divisible(10));
  33.   WriteLn('Expression: ', (Number + 5).Divisible(10));
  34. end.
« Last Edit: September 14, 2018, 11:06:17 am by Thaddy »
Ada's daddy wrote this:"Fools are my theme, let satire be my song."

furious programming

  • Jr. Member
  • **
  • Posts: 68
  • I click a little.
    • TreeStructInfo - format for text and binary configuration files
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #11 on: September 14, 2018, 04:19:55 pm »
I wish people referring to "the documentation" would first refer to the real documentation: the manuals. And not the wiki.

Of course, but in wiki it is clearly written (about dependence of modes). Real documentation describes this:

Quote
The integer type maps to the smallint type in the default Free Pascal mode. It maps to either a longint in either Delphi or ObjFPC mode.

This is first tip. Second tip is in bullet list:

Quote
1. Every platform has a ”native” integer size, depending on whether the platform is 8-bit, 16-bit, 32-bit or 64-bit. e.g. On AVR this is 8-bit.

Hmm… And the third tip is in point 3. b. (points a. and c. are not applicable in my case):

Quote
3. The result of binary arithmetic operators (+, -, *, etc.) is determined in the following way:
b. If both operands have the same signedness, the result is the same type as them. The only exception is subtracting (-): in the case of unsigned-unsigned subtracting produces a signed result in FPC (as in Delphi, but not in TP7).

In summary, if the numeral literal (in my case 5) is an Integer, and the Integer type is 32-bit wide in ObjFPC mode on 64-bit platform, the result of expression must be 32-bit wide and my TIntegerHelper must be used.

As far as I can see, it is not like that at all. If the point 3. b. is true, the numeral literal on 64-bit platform is not 32-bit wide, so the compiler behavior is correct and I need helper for Int64. I do not understand something here—what is the type of literal 5 on 64-bit platform? Int64? Is it treated the same way as ordinal constants or in different way?

Please be patient, I would like to understand it thoroughly and no longer have any doubts. Thank you for help.
« Last Edit: September 14, 2018, 05:44:35 pm by furious programming »

Bart

  • Hero Member
  • *****
  • Posts: 3078
    • Bart en Mariska's Webstek
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #12 on: September 14, 2018, 09:27:39 pm »
If I understand the documentation correctly then rule 3c applies.
Number is signed, the literal 10 is treated by the compiler as byte (SizeOf(10) gives 1), so you mix signed and unsigned operands, and the compiler will use a "larger signed result", in this case Int64.

Bart

furious programming

  • Jr. Member
  • **
  • Posts: 68
  • I click a little.
    • TreeStructInfo - format for text and binary configuration files
Re: Simple type helper method fail on Lazarus 64-bit
« Reply #13 on: September 14, 2018, 10:43:47 pm »
Mhm, sounds good. Ok, thank you all for your help.

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus