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

Comments

  1. Will this play nicer?

    function 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.

    ReplyDelete
  2. That's why temporal coupling is bad.

    Imo the 32bit code should fail. Calling CreateListAndAddItem before GetList seems to be some kind of optimization (yes, it does it regardless the $O option).

    ReplyDelete
  3. 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.

    ReplyDelete
  4. Just so I mentioned it. The call order on 32-bit has nothing to do with the default index property. This has the same behavior:

    GetList.Delete(CreateListAndAddItem);

    ReplyDelete
  5. 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.

    On 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!

    ReplyDelete
  6. 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.

    ReplyDelete
  7. I 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.

    ReplyDelete
  8. Lars 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.

    Since this part of the language is undocumented, only Embarcadero can know.

    ReplyDelete

Post a Comment