Jump to content
pyscripter

Generic Type Inference

Recommended Posts

The following statement compiles under Delphi 11 64 bits but produces an error in 32 bits.

 

Assert.AreEqual(Rec.SubRecord.DoubleField, 3.14);

[dcc32 Error] WrapDelphiTest.pas(357): E2532 Couldn't infer generic type argument from different argument types for method 'AreEqual'

 

Here is the definition of Assert.AreEqual

 

class procedure Assert.AreEqual<T>(const expected, actual: T; const message: string);

Any idea why?

Share this post


Link to post
Guest

If i would guess, then i will go this, considering compiler has a brain similar in size to a banana brain, it did handled the constant 3.14 as single then refused to compile.

 

Would replacing 

Assert.AreEqual(Rec.SubRecord.DoubleField, 3.14);

with 

Assert.AreEqual(Rec.SubRecord.DoubleField, Double(3.14));

helps ?

Share this post


Link to post

My guess is,  in 64 bit Double and Extended are the same and constants are Double, but in 32 bit they are different and constants are Extended. The DoubleField matches the Double and Extended type as well as the Extended constant does, so the compiler doesn't know what to select.

  • Like 1

Share this post


Link to post
Guest
8 minutes ago, Uwe Raabe said:

in 64 bit Double and Extended are the same and constants are Double, but in 32 bit they are different and constants are Extended. The DoubleField matches the Double and Extended type as well as the Extended constant does, so the compiler doesn't know what to select.

To confirm this theory i tried this

procedure WriteIt(V: Single); overload;
begin
  Write('Single = ');
  Writeln(V);
end;

procedure WriteIt(V: Double); overload;
begin
  Write('Double = ');
  Writeln(V);
end;

procedure WriteIt(V: Extended); overload;
begin
  Write('Extended = ');
  Writeln(V);
end;
 {
procedure WriteIt(V:Extended80);overload;
begin
  Write('Extended80 = ');
  Writeln(V);
end;  }

procedure Test;
begin
  WriteIt(3.14);
end;

Extended and Extended80 are the same type on both bitness builds, but also the compiler is choosing Extended(Extended80) on both platforms.

 

And that bring us back to the theory of banana brain !

It seems and might be true though, the monkey (compiler) start to dance when see generics (bananas) 

Share this post


Link to post
Guest
14 minutes ago, Uwe Raabe said:

That is for C++, while in Delphi 32 Bit they are Extended. See Declared Constants

Quote

If constantExpression is a real, its type is Extended.

 

Well, there is the following argument 

1) We are not talking constant expression, but simple untyped constant, this is very important though, as the behaviour even for constant integer expression one might call it buggy or inconsistent.

 

2) Now to my test above, the compiler didn't accept the existence of the Extended and Extended80 as overloaded, means they are identical types, but it accept Double and Extended and choose Extended, if we removed the Extended version, the compiler choose Double over Single, and if we left only Single the compiler will not complain and forward it there, all of that without a warning because it will be ugly and stupid to warn about such thing.

 

But it comes to the proc with generics, it failed to behave the same, i mean simple "3.14" is untyped and the compiler should have showed some personality and intuitive more than a banana ( or a car, i know you have a thing for such examples :classic_blush: ) , i see this as compiler bug or inconsistency in behaviour, what do you think ?

Share this post


Link to post

Same happens with Integers, you have to write for example

  Assert.AreEqual(1, Integer(Length(smth)));

it is very annoying, I wonder if there is a way to fix it in DunitX?

Share this post


Link to post
Guest
18 minutes ago, EugeneK said:

it is very annoying, I wonder if there is a way to fix it in DunitX?

I think the compiler should be fixed first before fixing any library, because fixing generics or DUnitX based on faulty compiler is just wrong and will breaks things even more.

 

example :

This will not compile, on both 32bit and 64bit.

var
  UI64: UInt64;
begin
  UI64 := 1 shl 31;   // [dcc64 Error] : E1012 Constant expression violates subrange bounds
  //  also this 
var
  UI32: Cardinal;
begin
  UI32 := 1 shl 31;

While this will compiler fine 

var
  UI64: UInt64;
begin
  UI64 := 1 shl 32;   // UI64 value is 1

there is so many wrong with constants and even more problem with constant expressions that can be listed in one post.

Share this post


Link to post
Guest

adding one more exotic example, just to point to a fact that a Delphi application by luck works to some extend

const
  T: Integer = 1;

procedure Test;
var
  UI64: UInt64;
begin
  UI64 := T shl 31;    // UI64 = 18446744071562067968 !!!!!!!!!!!!!!!!

 

Share this post


Link to post
Guest

Three more of these gems, in case someone thinks the bug in bit shifting (shl)

const
  T: Integer = 1;

procedure Test;
var
  UI64: UInt64;
begin
  //  this is fine
  UI64 := T * 256 * 256 * 256 * 64;   // = 1073741824  

  //  WTF with the following error
  UI64 := 1 * 256 * 256 * 256 * 128;   // [dcc64 Error] : E2099 Overflow in conversion or arithmetic operation   
  
  //  This is fine
  UI64 := Int64(1) * 256 * 256 * 256 * 256;   // = 4294967296

  //  Again WTF
  UI64 := T * 256 * 256 * 256 * 128;   // = 18446744071562067968

 

Share this post


Link to post
8 hours ago, EugeneK said:

it is very annoying, I wonder if there is a way to fix it in DunitX?

I'm open to suggestions - but really this is a Delphi compiler issue and I'm not sure what else I could do to work around it.

Share this post


Link to post
On 9/14/2021 at 12:39 PM, Kas Ob. said:

Three more of these gems, in case someone thinks the bug in bit shifting (shl)


const
  T: Integer = 1;

procedure Test;
var
  UI64: UInt64;
begin
  //  this is fine
  UI64 := T * 256 * 256 * 256 * 64;   // = 1073741824  

  //  WTF with the following error
  UI64 := 1 * 256 * 256 * 256 * 128;   // [dcc64 Error] : E2099 Overflow in conversion or arithmetic operation   
  
  //  This is fine
  UI64 := Int64(1) * 256 * 256 * 256 * 256;   // = 4294967296

  //  Again WTF
  UI64 := T * 256 * 256 * 256 * 128;   // = 18446744071562067968

 

 

I get E2099 in 10.4.2 at compile time so it's not a new issue.

In RS11 I get integer overflow at runtime on the last one so there is some change in default behavior since 10.4.2

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×