Nullable
In Dart, a nullable variable is one that can hold a null
value, meaning it might have no value at all. This concept is important in languages like Dart that enforce null safety, where variables must either explicitly allow nulls or be guaranteed to hold a non-null value.
Declaring Nullable and Non-Nullable Variables
In Dart, all variables are non-nullable by default. This means that a variable cannot be null unless we explicitly mark it as nullable by adding a question mark ?
after its type. Here’s how it works:
int a; // Non-nullable: cannot hold `null`
int? b; // Nullable: can hold `null`
In this example:
a
is a non-nullable integer, so we have to assign a value before using it.b
is a nullable integer, so it can hold either an integer value ornull
.
Checking for Null
To safely access or manipulate a nullable variable, we need to check if it’s null
before using it. Dart provides several ways to handle nullable variables:
- Using
if
statements:int? b; if (b != null) { print(b + 5); // Safe to use `b` here }
-
Null-aware operators: Dart includes several operators to work with nullable values efficiently.
- Null-aware assignment (
??=
): This assigns a value to a nullable variable only if it’s currentlynull
.int? b; b ??= 10; // Assigns 10 to `b` if `b` is null print(b); // Output: 10
- Null-coalescing operator (
??
): This provides a fallback value if the variable isnull
.int? b; int result = b ?? 0; // Uses 0 if `b` is null print(result); // Output: 0
- Null-aware access (
?.
): This allows we to access a member of an object only if it isn’tnull
.String? name; print(name?.length); // Safe; returns null if `name` is null
- Null-aware assignment (
-
Type promotion with
if
: When we check a nullable variable with anif
statement, Dart promotes it to a non-nullable type within that scope, meaning we don’t need extra syntax to use it safely.int? b; if (b != null) { print(b + 5); // `b` is promoted to non-nullable here }
- The
late
keyword: If we’re certain a variable will be initialized later but can’t assign a value immediately, we can uselate
:late int a; a = 10; print(a); // Output: 10
Null Assertion Operator
In addition to the techniques mentioned above, Dart also provides the null assertion operator, denoted by the exclamation mark !
. This operator tells the Dart compiler that the variable is guaranteed not to be null
at that point in the code.
Here’s an example:
String? name = "John Doe";
print(name!.toUpperCase()); // Output: JOHN DOE
In this example, name
is declared as a nullable String
. The !
after name
tells Dart that we are certain name
is not null
, so it’s safe to call the toUpperCase()
method on it without an additional null
check.
However, it’s important to be careful when using the null assertion operator, as it can lead to runtime errors if the variable is actually null
at the time of access. If you’re not absolutely sure the variable is not null
, it’s generally better to use the null-aware operator ?.
or an if
statement to handle the null
case gracefully.
Example Usage
Here’s an example showing how nullable variables work in practice:
void printName(String? name) {
// Providing a default name if `name` is null
print("Hello, ${name ?? 'Guest'}!");
}
void main() {
String? userName;
printName(userName); // Output: Hello, Guest!
userName = "Alice";
printName(userName); // Output: Hello, Alice!
}
In this example, name
is a nullable String
, so it can hold null
. When null
is passed to printName
, it defaults to “Guest”. When a name is assigned, that name is used instead.
Summary
- Use
?
after the type to declare a nullable variable. - Use
??
,??=
, and?.
operators for safe null handling. - Use type promotion in
if
statements to handle nullable variables. - Use
late
for variables we guarantee will be initialized before use. - Use the null assertion operator
!
with caution, only when you are certain the variable is notnull
.
This null safety system in Dart helps reduce runtime errors by enforcing nullable and non-nullable distinctions at compile-time.