PiedSoftware 3 Posted September 25 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 1 Share this post Link to post
David Heffernan 2353 Posted September 25 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 1 Share this post Link to post
PiedSoftware 3 Posted December 4 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
Remy Lebeau 1421 Posted December 4 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
David Heffernan 2353 Posted December 5 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. 4 Share this post Link to post
Brian Evans 109 Posted December 5 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
David Heffernan 2353 Posted December 5 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
PeterBelow 239 Posted December 6 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
David Heffernan 2353 Posted December 6 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
Lars Fosdal 1793 Posted December 7 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