IceCold
IceCold

Reputation: 21192

OUT parameter is not behaving according to the documentation

On Emba's website, it is stated that an OUT parameter (does not say which type, so I assume it applies to all types) should not be used for input because its value is "discarded".

Screenshot, to last for eternity :) "enter image description here"

By discarded, I interpret (even though we are not at the Bible Study hour) that whatever value is present in that variable is thrown away and the variable is zeroed.
Update: from the discussion in the comments I think that the English word "disregarded" or "ignored" would be more accurate.

With an out parameter, however, the initial value of the referenced variable is discarded by the routine it is passed to.

But this simple code shows that the value stored in "i" is not zeroed, but a string "s" is. So the behavious of OUT is not only inconsistent but ALSO undocumented.

TYPE TMyRec = record
  i: Integer;
end;

Procedure TestInteger(OUT i: Integer);
Begin
End;

Procedure TestRec(OUT R: TMyRec);
Begin
End;

Procedure TestStr(OUT S: string);
Begin
End;

procedure TfrmTest.btnTestRecClick(Sender: TObject);
begin
  VAR MyRecord: TMyRec;
  MyRecord.i:= 7;
  TestRec(MyRecord);
  Memo.Lines.Add('Test rec: '+ IntToStr(MyRecord.i));
end;

procedure TfrmTest.btnTestStrClick(Sender: TObject);
begin
  VAR s: string:= 'x';
  TestStr(s);
  Memo.Lines.Add('Test str: '+ s);
end;

procedure TfrmTest.btnTestIntClick(Sender: TObject);
begin
  VAR i: Integer:= 7;
  TestInteger(i);
  Memo.Lines.Add('Test int: '+ IntToStr(i));
end;

enter image description here

The documentation also says:

But you're not using MyRecord to pass any data to the GetInfo procedure; MyRecord is just a container where you want GetInfo to store the information it generates. The call to GetInfo immediately frees the memory used by MyRecord, before program control passes to the procedure.

But my test code shows that the memory for me record was not zeroed.

So, is the documentation wrong? Is simply the wording wrong? Maybe they meant "ignored" instead of "discarded"? Why is Emba using such confusing words when better alternatives are available?


Update:
Another confirmation that the behavior of the OUT param is not only poorly documented but also inconsistent: The article shows that managed things are always nullified.
https://delphisorcery.blogspot.com/2021/04/out-parameters-are-just-bad-var.html

Upvotes: 1

Views: 430

Answers (2)

Brian
Brian

Reputation: 7299

Note that if you use a managed record it does call initialize and a 0 ends up in the caption.

TYPE TMyRec = record
  i: Integer ;
  class operator Initialize (out Dest: TMyRec);
end;

class operator TMyRec.Initialize (out Dest: TMyRec);
begin
  dest.i := 0;
end;

This is more of a comment but code doesn't format well in comments.

Upvotes: 1

Andreas Rejbrand
Andreas Rejbrand

Reputation: 109003

Decorating a parameter with out means that the parameter will only be used to return a value to the caller; the routine must not make any assumption about the initial value of the parameter.

The out decoration serves as a semantic hint to the programmer. In addition, the compiler may use the knowledge that the "passed" value will not be used to optimize the generated code.

However, there is no guarantee whatsoever that a "passed" value is indeed cleared. After all, such a guarantee would serve no purpose; on the contrary, it would likely force the compiler to generate slightly less efficient code (because zeroing memory takes time).

Think of a watch manufacturer that makes watches able to function properly down to −50°C. You then make an order for a watch that only needs to be able to function properly down to −20°C. The manufacturer may use this knowledge to produce the watch more cheaply. However, there is absolutely no guarantee that the watch you are delivered will malfunction at −50°C, nor would you typically need such a guarantee. (But of course you must not use the watch below −20°C.)

With an out parameter, however, the initial value of the referenced variable is discarded by the routine it is passed to.

Well, since the programmer never uses the value, it is effectively "discarded", isn't it?

A bit later down on the same page:

The call to GetInfo immediately frees the memory used by MyRecord, before program control passes to the procedure.

Okay, this is hard not to consider as erroneous.

Upvotes: 3

Related Questions