What is the expected call order for this?
What is the expected call order for this?
if GetList[CreateListAndAddItem] = nil then
WriteLn('nil');
when:
var
List: TList;
function GetList: TList;
begin
WriteLn('GetList');
Result := List;
end;
function CreateListAndAddItem: Integer;
begin
WriteLn('CreateListAndAddItem');
List := TList.Create;
Result := List.Add(nil); // return the index of the added item...0 in the case
end;
Is it CreateListAndAddItem then GetList or vice versa? Answer: It depends.
Compiled as 32 bit target it's CreateListAndAddItem then GetList but compiled for 64 it's reversed (and the code obviosly crashes).
I opened a bugreport for that: https://quality.embarcadero.com/browse/RSP-10012
if GetList[CreateListAndAddItem] = nil then
WriteLn('nil');
when:
var
List: TList;
function GetList: TList;
begin
WriteLn('GetList');
Result := List;
end;
function CreateListAndAddItem: Integer;
begin
WriteLn('CreateListAndAddItem');
List := TList.Create;
Result := List.Add(nil); // return the index of the added item...0 in the case
end;
Is it CreateListAndAddItem then GetList or vice versa? Answer: It depends.
Compiled as 32 bit target it's CreateListAndAddItem then GetList but compiled for 64 it's reversed (and the code obviosly crashes).
I opened a bugreport for that: https://quality.embarcadero.com/browse/RSP-10012
Will this play nicer?
ReplyDeletefunction GetList: TList;
begin
if not Assigned(List)
then List := TList.Create;
Result := List;
end;
function CreateListAndAddItem: Integer;
begin
Result := GetList.Add(nil);
end;
I guess it is different types of optimization that comes into play here.
That's why temporal coupling is bad.
ReplyDeleteImo the 32bit code should fail. Calling CreateListAndAddItem before GetList seems to be some kind of optimization (yes, it does it regardless the $O option).
Agree with Stefan Glienke; I'd interpret GetList[CreateListAndAddItem] as short for GetList().Items[CreateListAndAddItem], and therefore would expect GetList() to be called first, and only then CreateListAndAddItem.
ReplyDeleteJust so I mentioned it. The call order on 32-bit has nothing to do with the default index property. This has the same behavior:
ReplyDeleteGetList.Delete(CreateListAndAddItem);
The Delphi documentation does not specify the execution order of the sub-expressions here. So perhaps the compiler is free to do what it pleases and this behaviour is as designed.
ReplyDeleteOn the other hand, perhaps the fact that the documentation fails to specify the behaviour is an omission. In which case one of the compilers is wrong!
Stefan Glienke My take on properties is that they are pure sugar and that the front end transforms the code to the non-property equivalent and then compiles that. Just as for-in loops are sugar.
ReplyDeleteI am not so sure that we can say that the 32-bit compiler is wrong either. It just lines up the data in a different order. Depending on the code following the statements - the optimizer theoretically could swap the retrieval order to reduce the number of register, stack or memory exchanges.
ReplyDeleteLars Fosdal It depends on what the specification of the language is. If the language does not specify an order there is no bug. If the language does specify an order, one of the compilers is wrong.
ReplyDeleteSince this part of the language is undocumented, only Embarcadero can know.