2

This is out of curiosity question. I stumbled upon this example while researching on ObjectBinaryToText behaviour for my previous question. Line 5 declares string variable and then code implicitly relies on the fact what long strings are managed and never initializes that string, and then uses to initialize TStringStream in line 9. I think this code is not 100% correct, but i would like to know WHY s has been included here? (dont see any rationale behind)

function ComponentToStringProc(Component: TComponent): string;
var
  BinStream:TMemoryStream;
  StrStream: TStringStream;
  s: string;                               // line 5
begin
  BinStream := TMemoryStream.Create;
  try
    StrStream := TStringStream.Create(s);  // line 9
    try
      BinStream.WriteComponent(Component);
      BinStream.Seek(0, soFromBeginning);
      ObjectBinaryToText(BinStream, StrStream);
      StrStream.Seek(0, soFromBeginning);
      Result:= StrStream.DataString;
    finally
      StrStream.Free;
    end;
  finally
    BinStream.Free
  end;
end;

Source: documentation entry.

rene
  • 41,474
  • 78
  • 114
  • 152
Premature Optimization
  • 1,917
  • 1
  • 15
  • 24

2 Answers2

2

That's just slightly sloppy code. It should be written like this:

StrStream := TStringStream.Create;

The variable s is not needed, but since it is managed it is initialised to nil and so the meaning of the code is correct. So in the code in your question, s = '' and thus that code is equivalent to calling the parameterless constructor.

Even if the reason is as Mason hypothesises (and it's certainly plausible), the code should have been written TStringStream.Create('') to work on older versions of Delphi that lacked the parameterless constructor.

One side effect of declaring s in the code in your question is that an unnecessary implicit try/finally block is added around the method. Again this is benign but you may as well avoid it.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Does that mean that interfaces are initialized to `nil` as well? That's good to know. – jpfollenius Jun 20 '11 at 19:13
  • @smasher strings, interfaces, dynamic arrays, anonymous methods - I think that covers everything. – David Heffernan Jun 20 '11 at 19:16
  • 1
    @Rob Argh, you beat me to it by 20 seconds! I think that's really it now though: http://stackoverflow.com/questions/861045/which-variables-are-initialized-when-in-delphi – David Heffernan Jun 20 '11 at 19:40
  • ... and records containing reference counted types (and note that strings = AnsiString + UnicodeString + WideString here), even recursively. It's done in the `_InitializeArray()` low-level procedure in System.pas unit for dynamic arrays and record, and by auto-generated code initializing the stack for local variables. :) – Arnaud Bouchez Jun 21 '11 at 05:31
2

Hard to say for sure, but if I had to guess, the answer would probably be something along the lines of "TStringStream doesn't require a string to be passed to the constructor in current versions, but in earlier versions of Delphi it did, and this code is very old, (probably dating all the way back to D1) so it's still written that way because it works just fine and no one's ever gone through and changed it."

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • That would still not explain why a string variable is created instead of just passing an empty string constant. – jpfollenius Jun 20 '11 at 19:07
  • @smasher: It's late and I've had a couple of Guinness but in the (old) code you may have got the error "Data Types must be Identical"? – Despatcher Jun 20 '11 at 21:04
  • @Despatcher That would only have happened if the parameter had been declared as `var`. – David Heffernan Jun 20 '11 at 21:16
  • It took a while but i found out what assertion about string parameter is absolutely correct (no idea about D3, but since D4 it was). Also this parameter always was `const` (again, D4) – Premature Optimization Jun 20 '11 at 22:04