Jump to content
PiedSoftware

Type inference in assignment but not comparison??

Recommended Posts

I like the way Delphi is getting better at arrays, but there is still a gap in the compiler that let me down. 

I tried this code in 12.2 to highlight the issue.
 


const nostrings: tarray<string> = [];

procedure TForm1.FormShow(Sender: TObject);
begin
  var a: tarray<string>;
  a := [];
  if a = nostrings then
    say('nostrings');
  if a = [] then
    say('it''s blank');
end;

procedure TForm1.say(const s: string);
begin
  ListBox1.Items.Add(s);
end;

This refuses to compile at the line

 if a = [] then

with the error "Incompatible types". But it has no problem with the assignment, so it looks like the programmers have just put this in the "do eventually" basket.

Does anyone have any insights into this?

--- Mark 

  • Sad 1

Share this post


Link to post
4 hours ago, PiedSoftware said:

Does anyone have any insights into this?

 

Delphi doesn't know that you want [] to be an array rather than a set. Because the language has been designed iteratively and there is ambiguity. Delphi literals are a bit of a mess.

 

In any case are you sure that you want to use = with a reference type? That's reference identity and not value identity.

 

You will need to test for Length(a)=0 or not Assigned(a) or a = nil

  • Like 1

Share this post


Link to post
On 9/25/2024 at 6:38 PM, David Heffernan said:

 

Delphi doesn't know that you want [] to be an array rather than a set. Because the language has been designed iteratively and there is ambiguity. Delphi literals are a bit of a mess.

 

In any case are you sure that you want to use = with a reference type? That's reference identity and not value identity.

  

You will need to test for Length(a)=0 or not Assigned(a) or a = nil

Thanks for thinking about it Dave. But ...
It already knows the type of a to be an array, so a set interpretation is ruled out.
And for arrays, nil and [] mean the same thing. That is why the assignment operator works. So, I think it is reasonable to expect the compile to test for equality with the same syntax.

Share this post


Link to post
1 hour ago, PiedSoftware said:

So, I think it is reasonable to expect the compile to test for equality with the same syntax.

Then you should open a ticket with Embarcadero asking for that.

Share this post


Link to post
On 12/4/2024 at 5:39 AM, PiedSoftware said:

Thanks for thinking about it Dave. But ...
It already knows the type of a to be an array, so a set interpretation is ruled out.
And for arrays, nil and [] mean the same thing. That is why the assignment operator works. So, I think it is reasonable to expect the compile to test for equality with the same syntax.

 

Not sure who Dave is....

 

Delphi doesn't know that the type of the thing to the right of the equality operator is an array, it thinks it is a set. That's why you get the error. You might not like this, but this is just how it is right now.

 

From the language perspective, there is clearly some magic disambiguation applied in the case of the assignment operator that isn't applied elsewhere. As Remy says, all you can do is to open a ticket. Shooting the messenger isn't going to get you anywhere.

 

But even if the code did compile, what would you want it to do? For dynamic arrays, like other reference types, the equality operator = means reference equality. But I suspect that you would want value equality. So even if this code ever compiled, I don't think it would do what you want to do. In which case you will need to implement a method or function to perform value equality testing, and so the topic becomes somewhat moot.

  • Like 4

Share this post


Link to post

From my understanding: expressions always evaluate the same and it is the assignment operation doing type conversions when they are straightforward. That works for assignment because there is a variable on the left of a specific type and not an expression and they are never reversed. A comparison has an expression on both sides and can be reversed so type conversion on corner cases could mean A = B and B = A give different results. Better to have the programmer explicitly make each expression evaluate to the same type or at least be stricter than what happens on assignment. 

Share this post


Link to post
3 hours ago, Brian Evans said:

From my understanding: expressions always evaluate the same and it is the assignment operation doing type conversions when they are straightforward. That works for assignment because there is a variable on the left of a specific type and not an expression and they are never reversed. A comparison has an expression on both sides and can be reversed so type conversion on corner cases could mean A = B and B = A give different results. Better to have the programmer explicitly make each expression evaluate to the same type or at least be stricter than what happens on assignment. 

 

This is a really good point, and very nicely expressed.

 

Essentially the whole thing boils down to Delphi literals having ambiguity of type. Sets and arrays use the same syntax. For integers, what type is 1, how can I make sure that it is signed or unsigned, 8 bit, 16 bit etc. And 1.0, is that single or double? Why can't I state this explicitly. Other languages have these facilities, Delphi lags behind in this area.

Share this post


Link to post
20 hours ago, David Heffernan said:

 

This is a really good point, and very nicely expressed.

 

Essentially the whole thing boils down to Delphi literals having ambiguity of type. Sets and arrays use the same syntax. For integers, what type is 1, how can I make sure that it is signed or unsigned, 8 bit, 16 bit etc. And 1.0, is that single or double? Why can't I state this explicitly. Other languages have these facilities, Delphi lags behind in this area.

But you can state it explicitely, just use an appropriate type cast, e.q. Smallint(1) instead of just 1.

Share this post


Link to post
Just now, PeterBelow said:

But you can state it explicitely, just use an appropriate type cast, e.q. Smallint(1) instead of just 1.

I actually don't know how that is interpreted by the compiler 

Share this post


Link to post
On 12/6/2024 at 2:38 PM, David Heffernan said:

I actually don't know how that is interpreted by the compiler 

It is at least interpreted correctly with regards to type and type size.

32-bit  SizeOf(Type(1))
1       Byte
1       UInt8
1       Int8
1       ShortInt
2       Word
2       Int16
2       UInt16
2       SmallInt
4       FixedInt
4       FixedUInt
4       Integer
4       Cardinal
4       NativeInt
4       NativeUInt
8       Int64
8       UInt64

 

64-bit  SizeOf(Type(1))
1       Byte
1       UInt8
1       Int8
1       ShortInt
2       Word
2       Int16
2       UInt16
2       SmallInt

4       FixedInt
4       FixedUInt
4       Integer
4       Cardinal
8       NativeInt
8       NativeUInt
8       Int64
8       UInt64

 

program TypeCastSizeOf;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

begin
{$ifdef CPU32Bits}
  Write('32-bit');
{$else}
  Write('64-bit');
{$endif}
  Writeln('  SizeOf(Type(1))');
  try
    try
      Writeln(SizeOf(Byte(1)),^I'Byte');
      Writeln(SizeOf(UInt8(1)),^I'UInt8');
      Writeln(SizeOf(Int8(1)),^I'Int8');
      Writeln(SizeOf(ShortInt(1)),^I'ShortInt');
      Writeln(SizeOf(Word(1)),^I'Word');
      Writeln(SizeOf(Int16(1)),^I'Int16');
      Writeln(SizeOf(UInt16(1)),^I'UInt16');
      Writeln(SizeOf(SmallInt(1)),^I'SmallInt');
      Writeln(SizeOf(FixedInt(1)),^I'FixedInt');
      Writeln(SizeOf(FixedUInt(1)),^I'FixedUInt');
      Writeln(SizeOf(Integer(1)),^I'Integer');
      Writeln(SizeOf(Cardinal(1)),^I'Cardinal');
      Writeln(SizeOf(NativeInt(1)),^I'NativeInt');
      Writeln(SizeOf(NativeInt(1)),^I'NativeUInt');
      Writeln(SizeOf(Int64(1)),^I'Int64');
      Writeln(SizeOf(UInt64(1)),^I'UInt64');

    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    Readln;
  end;
end.


 

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

×