When exceptions like EZeroDivide
, EOverflow
, EMathError
... are raised, they appear with a default message.
For example, the following code raises an EZeroDivide
with the following message:
Floating point division by zero
procedure TForm1.Button1Click(Sender: TObject);
var
N : Extended;
D : Extended;
begin
N := 100;
D := 0;
Caption := FloatToStr(N/D);
end;
When I "manually" raise an EZeroDivide
exception by code, I have to pass the Msg
parameter to the constructor and it is raised as an EZeroDivide
exception which have an empty string message:
procedure TForm1.Button2Click(Sender: TObject);
begin
raise EZeroDivide.Create('');
end;
Where does default exception messages come from?
Those exception instances are generated internally by the RTL. The specific string in the question can be found in the resourcestring
section of SysConst.pas
SZeroDivide = 'Floating point division by zero';
Internally the RTL uses the Error
method to raise such exceptions. The full list of runtime errors is defined in the System
unit in the following enum :
TRuntimeError = (reNone, reOutOfMemory, reInvalidPtr, reDivByZero,
reRangeError, reIntOverflow, reInvalidOp, reZeroDivide, reOverflow,
reUnderflow, reInvalidCast, reAccessViolation, rePrivInstruction,
reControlBreak, reStackOverflow,
{ reVar* used in Variants.pas }
reVarTypeCast, reVarInvalidOp,
reVarDispatch, reVarArrayCreate, reVarNotArray, reVarArrayBounds,
reAssertionFailed,
reExternalException, { not used here; in SysUtils }
reIntfCastError, reSafeCallError,
reMonitorNotLocked, reNoMonitorSupport
{$IF defined(LINUX) or defined(MACOS) or defined(ANDROID)}
, reQuit
{$ENDIF LINUX or MACOS or ANDROID}
{$IFDEF POSIX}
, reCodesetConversion
{$ENDIF POSIX}
, rePlatformNotImplemented, reObjectDisposed
);
If you have a genuine reason for raising a runtime error yourself you can do it by calling, for example :
System.Error(reZeroDivide);
If you're very observant, you'll notice that Error
does not have a forward declaration in the System
unit but exists only in the implementation section. Typically this would prevent you from having visibility to call the method outside of its containing unit, but the System
unit is special in many ways and this method is accessible globally. Just beware that you will also often be including the Windows
unit and this declares a const named ERROR
which will usually hide System.Error
, so scoping it explicitly is usually required.