Enter a floating-point literal in the form below and it will display the exact decimal value in Extended, Double, and Single formats.
Delphi Q&A
A resource for in-depth Delphi answers
-
What is the exact value of a floating-point variable?
Published Monday, April 19th, 2010
-
Why do I continue getting error messages even after I have written an exception handler?
Published Wednesday, June 6th, 2007
In its default settings, the Delphi IDE notifies you whenever an exception occurs in your program, as in Figure 1. What’s important to realize is that at that point, none of your program’s exception-handling code has run yet. It’s all Delphi itself; its special status as a debugger allows it to get first notification of any exception in your program, even before your program knows about it.
Figure 1
An IDE-generated dialog box notifying that an exception occurred in the program being debugged
After you dismiss Delphi’s message box, execution will be paused at the best line of your source code Delphi could find to represent the source of the exception. Press the “Run” button to have your program resume. Control will pass to the next
finally
orexcept
block. Before you resume your program, you may use the various debugging tools at your disposal. You can inspect the values of any variables in scope, and you can even modify their values.Avoiding notification
If you do not want to be notified when an exception occurs, you have a few options.
-
You can use Delphi’s “advanced breakpoints” to disable exception handling around a region of code. To begin, set a breakpoint on the line of code where you want the IDE to ignore exceptions. Right-click on the breakpoint dot in the gutter and open the breakpoint-property dialog. In the advanced section are some check boxes. (See Figure 2.) Clear the “Break” box to prevent the debugger from interrupting your program at that line, and set the “Ignore subsequent exceptions” box.
Afterward, set another breakpoint where you want the debugger to resume handling exceptions. Change its properties to handle subsequent exceptions.
Figure 2
The breakpoint-property dialog box with the advanced section visible for changing exception-handling behavior
-
You can tell the debugger to ignore certain kinds of exceptions. Figure 3 shows Delphi’s language-exception options. Add an exception class to the list, and all exceptions of that type and of any descendant types will pass through to your program without Delphi interfering.
Figure 3
Delphi 2005 dialog for controlling language exceptions
-
In an option related to the previous one, you can tell the debugger not to interrupt on any exceptions. To do that, clear the “Notify on language exceptions” check box.
-
Finally, you can turn off integrated debugging altogether. Delphi will not notify you of exceptions, and it will also not stop at breakpoints or allow use of the “Pause” button. Turn off integrated debugging in the debugger options, as shown in Figure 5 for Delphi 2005.
Figure 4
Delphi 2005 dialog for disabling integrated debugging: Clear the “Integrated debugging” check box
-
-
Why doesn’t
Sleep(1)
pause for just one millisecond?Published Tuesday, June 5th, 2007
Some people wonder why the
Sleep
function pauses the program for more than just one millisecond even when thedwMilliseconds
parameter is set to1
. The reason is pretty clear, if you just consider what the documentation actually says.- dwMilliseconds
[in] The minimum time interval for which execution is to be suspended, in milliseconds.
A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution.
A value of
INFINITE
indicates that the suspension should not time out.
The key part of that is the first paragraph. It says that the parameter is the minimum interval. When a program calls
Sleep(1)
, it will be suspended for at least one millisecond, but possibly—probably—more.Infinite wait time
The documentation says
Sleep
will acceptInfinite
for its timeout. That’s not a good idea to try because then the function will never time out. TheInfinite
timeout is provided for other, related wait functions, such asSleepEx
, which can be interrupted before timing out.
-
When should I use
FreeAndNil
?Published Tuesday, June 20th, 2006
Borland introduced the
FreeAndNil
procedure in Delphi 5. It frees an object while ensuring that the object reference passed in will benil
afterward, even if freeing the object results in an exception.Uses
The only reason to set a variable to
nil
(or to any value, for that matter) is if some later portion of the program relies on the variable having that value. Otherwise, the assignment statement is just wasted code.The Delphi compiler does not perform the kind of interprocedural analysis necessary to recognize and hint about the ineffectiveness of calling
FreeAndNil
on a variable that will never be accessed again. It always assumes that a var parameter will be used somewhere else that it cannot detect.The parameter
FreeAndNil
takes an untyped var parameter. Why not declare it asTObject
? If it had a type, then the compiler’s type checking would interfere with the convenience of calling the function. If the variable passed to a type-explicitFreeAndNil
were not declared asTObject
, there would be a compiler error: “Types of actual and formal var parameters must be identical.”Since
FreeAndNil
is supposed to work on anyTObject
descendant, it cannot take a typed var parameter. The trade-off is that with an untyped parameter,FreeAndNil
will also accept non-TObject
types. There is nothing to prevent you from accidentally passing a genericGetMem
-allocated pointer toFreeAndNil
, although you’ll get get an error at run time. (For regular pointers, you can write your ownFreeMemAndNil
procedure or use the one provided in the JCL.)The name
Some argue that
FreeAndNil
should actually be namedNilAndFree
because that is the order of operations in Borland’s implementation. The function stores the object reference into a local variable, sets the original argument tonil
, and then callsFree
on the local. It does that to ensure that the argument isnil
even in the event of an exception while freeing the object. To implement the function in the order that its name suggests, a try-finally block could have been used, like so:Listing 1
An alternative
FreeAndNil
implementationprocedure FreeAndNil(var Obj);
begin
try
TObject(Obj).Free;
finally
TObject(Obj) := nil;
end;
end;There is nothing wrong with that code, except that Borland’s implementation provides nearly identical results without the overhead of setting up and tearing down an exception frame. The difference in results occurs when the actual argument passed to the function is a global variable or otherwise shared among multiple sections of a program. When that is the case, if code invoked by the object’s destructor accesses the shared variable, it will find that the variable’s value is already
nil
when using Borland’sFreeAndNil
, but it will find the variable unchanged when using the alternative implementation in Listing 1.
-
What is an untyped parameter?
Published Tuesday, June 20th, 2006
An untyped parameter is one that is declared without a type. Delphi frequently uses untyped parameters when a function needs to be able to accept arguments of any type. To assign some type to those parameters would cause type-mismatch errors when a program tried to call the functions.
Often, a function that uses an untyped parameter should not really accept just any parameter type. For example,
SysUtils.Supports
should only accept interface variables, but the compiler will not object to variables of other types, such asInteger
orstring
. Delphi has no middle-ground, though, for expressing that a parameter should be a certain kind of type. Untyped parameters completely circumvent the compiler’s type checker, so when using untyped parameters, remember that type-safety is not a guarantee.Below are some examples of functions that use untyped parameters.
System.Move
Listing 1
The
Move
procedureprocedure Move(const Source; var Dest; Count: Integer);
The
Move
procedure copies data from an arbitrary variable into any other variable. It needs to accept sources and destinations of all types, which means it cannot require any single type. The procedure does not modify the value of the variable passed forSource
, so that parameter’s declaration usesconst
instead ofvar
, which is the more common modifier for untyped parameters.SysUtils.Supports
Listing 2
Two (of several) declarations of the
Supports
functionfunction Supports(const Instance: IInterface; const IID: TGUID; out Intf): Boolean; overload;
function Supports(const Instance: TObject; const IID: TGUID; out Intf): Boolean; overload;The
Supports
function determines whether a given object implements a particular interface, optionally returning a reference to the object’s interface. The third parameter, if present, needs to be an interface-reference variable of the same type as the interface represented by the GUID given in the second parameter. (There is no way of expressing that requirement in code, so the compiler cannot check it for you.) That can be any interface type, so theIntf
parameter is declared as an untyped out parameter.The function uses
out
instead ofvar
because the function disregards any value already in the variable. Therefore, when you callSupports
, the variable you pass for the third parameter should not contain a valid interface reference. If it does, then Delphi will not reduce the object’s reference count, and so the object might never get freed.SysUtils.FreeAndNil
Listing 3
Declaration of the
FreeAndNil
functionprocedure FreeAndNil(var Obj);
FreeAndNil
needs to accept variables of anyTObject
-descended type, and it also needs to be able to assign new values to those variables. With a typed parameter, the compiler would try to enforce type safety every time a program called the function, and it would reject any call in which the actual parameter was of a different type than the formal parameter. This is explained in more detail in another article.TApplication.CreateForm
Listing 4
Function heading for
Application.CreateForm
procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
The Delphi IDE generates calls to
Application.CreateForm
when it adds a form to a project’s auto-create list. The first parameter is a class reference for the form to be created, and the second parameter is the variable that will receive a reference to the new object. See “Why shouldn’t I callApplication.CreateForm
?” for more information.As with
Supports
, the types ofCreateForm
’s parameters need to correspond to each other, but there is no way for the compiler to enforce that requirement. TheReference
parameter must be of the same type as the type passed toInstanceClass
.