A Nullable
type, is used to represent the presence or absence of a value. In programming languages where types are usually non-nullable (meaning variables cannot be assigned a null
or nil
value), a nullable type provides a way to express the absence of a value.
The concept of Nullable
is commonly used in languages like C#, Swift, Kotlin, and others. The idea is to allow a variable to be explicitly set to a special "null" value in addition to its regular type. This can be useful in various scenarios:
-
Database Interactions:
- When working with databases, certain fields in a record may not have a value. Instead of using a default value (e.g., zero or an empty string) to indicate the absence of data, a nullable type can be used.
-
Optional Function Parameters:
- When designing functions or methods, you might have parameters that are optional. Using a nullable type allows you to pass
null
for optional parameters, indicating that the parameter is not specified.
- When designing functions or methods, you might have parameters that are optional. Using a nullable type allows you to pass
-
Avoiding Ambiguous Values:
- In situations where a specific value is a valid input, using
null
as a separate indicator of absence can help avoid ambiguity. For example, if zero is a valid value, usingnull
to indicate "no value" prevents confusion.
- In situations where a specific value is a valid input, using
-
Avoiding Magic Values:
- Instead of using magic values that represent the absence of data (e.g., -1 or an empty string), nullable types provide a clear and type-safe way to express the absence of a value.
-
Error Handling:
- Nullable types can be useful in error-handling scenarios where the absence of a value indicates an error condition. For example, a function that searches for an element in a collection might return a nullable type to indicate that the element was not found.
Pascal does not have a built-in concept of nullable types similar to languages like C# or Swift. In Pascal, variables of simple types (like integers, strings, etc.) cannot be set to a null or undefined state.
However, there are some language features and conventions that can be used to achieve similar functionality.
TNullabe is an example of a simple way to create a nullable-like structure in Delphi using a record with a boolean flag.
Nullables in Delphi can be implemented using a record. All you need is a value, and some flag that will tell you whether or not the value has been explicitly set or not.
type
TNullable<T> = record
private
FHasValue: Boolean;
FValue: T;
function GetValue: T;
procedure SetValue(AValue: T);
public
property HasValue: Boolean read FHasValue;
property Value: T read GetValue write SetValue;
end;
In Delphi, records are not automatically initialized by default. Unlike objects or dynamic arrays, which are automatically initialized to a default state when created, records in Delphi are not automatically initialized to zero or any other default values.
The FHasValue boolean variable, that is non-managed or unmanaged type, can hold a random value.
In Delphi there are some language features that can be used to achieve record automatic initialization.
Delphi has introduced the concept of "Managed Records" as a language feature with the release of Delphi 10.4 Sydney, where record type supports custom initialization and finalization, beyond the default operations the compiler does for managed records.
type
TNullable<T> = record
private
FHasValue: Boolean;
....
{$IF (CompilerVersion >= 34)} // From RAD Studio 10.4 Sydney
class operator Initialize(out Dest: TNullable<T>);
class operator Finalize(var Dest: TNullable<T>);
{$ENDIF}
....
public
....
end;
Using Initialization, it is easy to implement automatic initialization of FHasValue.
{$IF (CompilerVersion >= 34)} // From RAD Studio 10.4 Sydney
class operator TNullable<T>.Initialize(out Dest: TNullable<T>);
begin
Dest.FHasValue := False;
end;
{$ENDIF}
Allen Bauer's post A "Nullable" Post
Dalija Prasnikar post Delphi Nullable with Custom Managed Records
Marco Cantu post Custom Managed Records Coming to Delphi 10.4
Barry Kelly post Smart pointers in Delphi
Synopse post ORM TNullable* fields for NULL storage
Spring4D Nullable implementation.
Landgraf.dev Nullable implementation.
Paulo Rossi Neon - JSON Serialization Library for Delphi and it's usage with JSON Serializer