Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi Tokyo exception prevents setting function result

Found that exception handling in Delphi Tokyo behaves a little different than in previous Delphi versions.

function FuncTest: integer;
begin
  Result := 1;
  try
    raise Exception.Create('Error Message');
  finally
    Result := 2;
  end;
end;

function Test:integer;
begin
  Result:=0;
  try
    Result:=FuncTest;
  finally
    ShowMessage(Result.ToString);
  end;
end;

In earlier Delphi versions the message box shows here "2", Tokyo - "0". Is this a Tokyo bug or the exceptions should not be handled like this?

like image 709
Molochnik Avatar asked Sep 28 '17 10:09

Molochnik


People also ask

What are the advantages of using exceptions in Delphi?

Abstract: Examples using try ... except and try .. finally This article provides some information on setting up error handling with Delphi. One of the big advantages of using exceptions is that you do not have to check the result of every function call that you make.

What do you do with the exception?

The next question may be what to do with the exception once you catch it. Sometimes, you may want to ignore certain exceptions (such as EConvertError), or execute certain code when an exception has been raised. If you don't handle the exception.

How does a VCL handle an exception?

From the point in the code at which it is raised, the exception is passed to its calling code, and so on. Ultimately, if no part of your code handles the exception, the VCL handles it, by displaying a standard error message and then trying to continue the program by handling the next system message or user request.

What are the advantages of exceptions in C programming?

One of the big advantages of using exceptions is that you do not have to check the result of every function call that you make. Typical C programming involves making a function call (such as allocmem) and checking the result to see if the function succeeded or not.


1 Answers

The Tokyo behaviour is correct. A function that raises an exception does not return a value. You have hitherto been relying on implementation detail.

Consider this code:

Result:=FuncTest;

This executes as follows:

  1. FuncTest is called.
  2. Result is assigned.

Now, because step 1 raises an exception, step 2 does not execute.

If anything, I would say that the behaviour you report from earlier versions is dubious. In this function:

function Test:integer;
begin
  Result:=0;
  try
    Result:=FuncTest;
  finally
    ShowMessage(Result.ToString);
  end;
end;

The statement Result:=FuncTest raises an exception and so Result should not be modified by that statement. Another way to think of it is that the function is called but the assignment is not executed.


One of the problems with the Delphi ABI is that function return values are sometimes implemented as implicit var parameters. Which means that the assignment may or may not happen. To demonstrate:

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

type
  TRec1 = record
    X1: NativeInt;
  end;

  TRec2 = record
    X1: NativeInt;
    X2: NativeInt;
  end;

function GetRec1: TRec1;
begin
  Result.X1 := 1;
  raise Exception.Create('');
end;

function GetRec2: TRec2;
begin
  Result.X1 := 1;
  raise Exception.Create('');
end;

procedure Main;
var
  Rec1: TRec1;
  Rec2: TRec2;
begin
  Rec1 := Default(TRec1);
  Writeln(Rec1.X1);
  try
    Rec1 := GetRec1;
  except
  end;
  Writeln(Rec1.X1);

  Rec2 := Default(TRec2);
  Writeln(Rec2.X1);
  try
    Rec2 := GetRec2;
  except
  end;
  Writeln(Rec2.X1);
end;

begin
  Main;
  Readln;
end.

This outputs:

0
0
0
1

Which is rather disappointing. It should not be possible to modify the caller's variable, but the use of an implicit var parameter rather than a value return allows this leakage. In my view this is a serious flaw in the design of the Delphi ABI, a flaw that you will not find in most other languages.


In your code, there is no var parameter because the return type is transferred in a register. In which case any Delphi version that outputs 2 is broken.

Fundamentally though, your code is mistaken in its expectations. If a function raises an exception then you must assume that the return value is ill-defined.

Finally, your code outputs 0 in XE3 and XE7, so I wonder how far back you need to go to see a value of 2.

like image 176
David Heffernan Avatar answered Oct 01 '22 03:10

David Heffernan