Quantcast
Channel: TMS Software
Viewing all articles
Browse latest Browse all 1006

Puzzling a Pascal developer with 33 years experience under the belt

$
0
0

Recently we received via our support a remark that the following Object Pascal code failed in a TMS WEB Core application

procedure TWebForm1.Button1Click(Sender: TObject);

  function TestFunction: TStringList;
  begin
    Result.Clear;
    Result.Add('ABC');
    Result.Add('DEF');
    Result.Add('GHI');
  end;
var
  StringList: TStringList;
begin
  StringList := TStringList.Create;
  try
    WebMemo1.Lines.Text := TestFunction.Text;
  finally
    StringList.Free;
  end;
end;
My immediate reaction and answer was "Of course, it is normal and expected this fails. One should create the result instance of a function inside the function".
But then came the reaction: "Well, it works in a VCL application, so it should work in TMS WEB Core too, not?" So, I tried the exact same code in a VCL application (with Delphi 10.2) where I added just a TMemo and a TButton and code:
procedure TForm1.Button1Click(Sender: TObject);

  function TestFunction: TStringList;
  begin
    Result.Clear;
    Result.Add('ABC');
    Result.Add('DEF');
    Result.Add('GHI');
  end;
var
  StringList: TStringList;
begin
  StringList := TStringList.Create;
  try
    Memo1.Lines.Text := TestFunction.Text;
  finally
    StringList.Free;
  end;
end;
and press compile & run and .... magic ... the compiler gave a warning but the code did add the 3 lines of text to the memo control. I thought that this must be some coincidence with the local variable TStringList memory overlapping the function Result memory and that for sure when compiling this for Win64 it would fail. And guess what... it keeps working! This is the point where I start to doubt everything I learned in 33 years of using the Pascal language. So, next step is testing this exact same code with the FPC compiler from Lazarus 2.0.2. My self-confidence is slowly going to zero as also there the code does add the 3 lines to the memo.

More playing around and changing the code to
function TestFunction: TStringList;
begin
  Result.Clear;
  Result.Add('ABC');
  Result.Add('DEF');
  Result.Add('GHI');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  StringList: TStringList;
begin
  StringList := TStringList.Create;
  try
    Memo1.Lines.Text := TestFunction.Text;
  finally
    StringList.Free;
  end;
end;
and the application is still doing the same, adding the 3 lines of text to the memo...

Not wanting to believe that 33 years of experience have been proven useless, I start playing with the code and modify it to:
procedure TForm1.Button1Click(Sender: TObject);

  function TestFunction: TStringList;
  begin
    Result.Clear;
    Result.Add('ABC');
    Result.Add('DEF');
    Result.Add('GHI');
  end;
var
  StringList: TStringList;
  s: string;
begin
  StringList := TStringList.Create;
  s := 'Hello world';
  try
    Memo1.Lines.Text := TestFunction.Text;
    Memo1.Lines.Add(s);
  finally
    StringList.Free;
  end;
end;
Aha, self-confidence is slowly coming back again as this fails gloriously with an access violation.

A small twist to the code:

procedure TForm1.Button1Click(Sender: TObject);

  function TestFunction: TStringList;
  begin
    Result.Clear;
    Result.Add('ABC');
    Result.Add('DEF');
    Result.Add('GHI');
  end;
var
  StringList: TStringList;
  s: string;
begin
  s := 'Hello world';
  StringList := TStringList.Create;
  try
    Memo1.Lines.Text := TestFunction.Text;
    Memo1.Lines.Add(s);
  finally
    StringList.Free;
  end;
end;
makes it 'work' again.

So, thinking that a class instance created just before invoking a function returning this class type will "just work" from Delphi, I now test it with the compiler set to Release mode instead of the default Debug mode and kaboom, the access violation now always comes. So, now I'm finally sure. One should never rely on creating a class instance outside a function returning this class type. The TMS WEB Core pas2js compiler also causes the equivalent error, i.e. invoking a method of a null, so relief, all is as expected in TMS WEB Core web client applications!

I'm curious to hear if you encountered similar confusing code patterns in your Delphi career?


Viewing all articles
Browse latest Browse all 1006


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>