Watch the video (10 min)
On this page25 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. 1. What Is null?
  5. 2. Where null Comes From
  6. 3. null Has Its Own Type
  7. 4. The Problem: Using a Value That Isn't There
  8. 5. What Null Safety Means
  9. 6. Your Types Do Not Allow null
  10. 7. A Guarantee You Can Trust
  11. 8. Object Doesn't Allow null Either
  12. 9. Why Lectures 004 and 006 Had Their Rules
  13. 10. Types That Say "Or Null": ?
  14. 11. A First Look at Nullable Variables
  15. 12. The Road Ahead
  16. 13. A Real-World Example
  17. Code Examples
  18. Common Beginner Mistakes
  19. Best Practices
  20. Mini Challenge
  21. Practice Questions
  22. Practice Answers
  23. Quick Revision
  24. Key Takeaways
  25. What's Next?

Lecture 12 — Introduction to Null Safety

Category3 — Null Safety
Lecture012 of 140
Estimated video length10 min
TargetDart 3.12.2
LevelBeginner

Real programs are full of missing values, and a missing value used by mistake used to crash the program. Null safety makes Dart catch that mistake before the program even starts.

Contents

Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways

Every error message in this lecture is real. Each one was produced by running the code shown on Dart 3.12.2, so you will recognize it when you meet it yourself.


Prerequisites

Students should already understand, from Lectures 004–011:

  • declaring variables with an explicit type and with var
  • why a variable cannot be read before it has a value (Lecture 004)
  • late as a promise that a value comes later (Lecture 006)
  • runtimeType, is, and int.tryParse returning null (Lecture 010)
  • the difference between Object and dynamic, and between compile-time and run-time errors (Lecture 011)

Connection With Previous Lectures

In Lecture 010, int.tryParse gave back a strange answer when the text was not a number:

dart
var age = int.tryParse('twenty'); // null

And several earlier lectures left a question open. Why must every variable in Lecture 004 have a value before it is read? Why does Lecture 006 need the late promise at all? And Lecture 011 hinted at one more difference between Object and dynamic. All three answers are the same thing: null, and the system Dart uses to keep it from crashing your programs.


Learning Objectives

By the end of this lecture you will be able to:

  • Explain what null means and where it comes from
  • Recognize null as the only value of the type Null
  • Describe the crash that null causes when it is used by mistake
  • Explain what null safety means in Dart
  • Recognize that String, int, double, and bool cannot hold null
  • Read the ? in a type such as int? as "or null"
  • Connect the rules from Lectures 004 and 006 to null safety
  • Recognize the error messages Dart produces when null is not allowed

1. What Is null?

null is Dart's value for "nothing here" — a value that is missing.

Analogy — think of a paper sign-up form. Sara fills in her first name, but leaves the "Middle name" box blank because she has none. The blank box is still an answer: it says "there is nothing here". In Dart, that blank box is null.

You can print it like any other value:

dart
void main() {
  print(null);
}
output
null

2. Where null Comes From

You have already met null once. In Lecture 010, int.tryParse returned null when the text was not a number, instead of crashing:

dart
void main() {
  var good = int.tryParse('42');
  var bad = int.tryParse('forty-two');
  print(good);
  print(bad);
}
output
42
null

bad holds no number at all. Real programs meet missing values all the time: a phone number nobody entered, a mark not recorded yet, a discount code the customer did not use.


3. null Has Its Own Type

Every value has a type, and so does null. Its type is called Null, and null is its only value:

dart
void main() {
  print(null.runtimeType);
  print(null is Object);
}
output
Null
false

The second line is the difference Lecture 011 promised. Every real value is an Object — but null is not a real value, so it is not an Object.


4. The Problem: Using a Value That Isn't There

What happens if you treat null as if it were text? dynamic switches Dart's checks off (Lecture 011), so we can see it:

dart
void main() {
  dynamic name = null;
  print(name.length);
}
output
Unhandled exception:
NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: length

You asked for the length of a name, but there was no name. The program crashed while running. Mistakes like this are among the most common crashes in programming — the inventor of null, Tony Hoare, later called it his "billion-dollar mistake".


5. What Null Safety Means

Null safety is Dart's protection against that crash. The rule is simple:

A variable can hold null only if its type says so.

Because of this rule, Dart knows before the program runs which variables might be missing, and refuses any code that could use a missing value by mistake. The crash from section 4 becomes a compile-time error — the safe kind from Lecture 011.

Null safety arrived in Dart 2.12 and has been required since Dart 3.0, so every Dart 3.12.2 program is null safe. You don't switch it on; it is always there.


6. Your Types Do Not Allow null

Every type you have used so far — String, int, double, bool — is non-nullable: it can never hold null.

dart
void main() {
  String name = null;
  print(name);
}
output
Error: A value of type 'Null' can't be assigned to a variable of type 'String'.
  String name = null;
                ^

The same is true later: assigning null to an int variable that already holds 20 is rejected in exactly the same way. Non-nullable is the default — you get it without writing anything.


7. A Guarantee You Can Trust

This default gives you a guarantee: if a variable's type is String, it really holds text.

dart
void main() {
  String name = 'Sara';
  int age = 18;
  print(name.length);
  print(age + 1);
}
output
4
19

name.length and age + 1 can never crash with the error from section 4. Dart has already proved that name and age are not null. Because the guarantee has no exceptions, Dart's null safety is called sound.


8. Object Doesn't Allow null Either

Object accepts every real value (Lecture 011) — but null is not one:

dart
void main() {
  Object item = null;
  print(item);
}
output
Error: A value of type 'Null' can't be assigned to a variable of type 'Object'.
 - 'Object' is from 'dart:core'.
  Object item = null;
                ^

dynamic, with its checks switched off, accepts null — which is why section 4 could crash. That is the extra difference between the two: Object means "any value", dynamic means "anything at all, even nothing".


9. Why Lectures 004 and 006 Had Their Rules

Now the old rules make sense. In Lecture 004, reading a variable before giving it a value was an error:

dart
void main() {
  String name;
  print(name);
}
output
Error: Non-nullable variable 'name' must be assigned before it can be used.
  print(name);
        ^^^^

Notice the word non-nullable. A String has no "empty" value to fall back on, so Dart insists on a real one first. A top-level variable gets the same rule:

dart
String name;

void main() {
  print(name);
}
output
Error: Field 'name' should be initialized because its type 'String' doesn't allow null.
String name;
       ^^^^

late (Lecture 006) is your way of saying "I know it has no value yet — trust me, it will before anyone reads it". Without null safety, Dart would not need that promise.


10. Types That Say "Or Null": ?

So how does a type "say so"? With a question mark. Look at what Dart reports when we try arithmetic on a tryParse result:

dart
void main() {
  var age = int.tryParse('20');
  print(age + 1);
}
output
Error: Operator '+' cannot be called on 'int?' because it is potentially null.
  print(age + 1);
            ^

Dart inferred the type int? — read it as "an int or null". Because tryParse might fail, its result might be missing, and Dart will not let you add to it. The same protection covers properties:

dart
void main() {
  String? middleName;
  print(middleName.length);
}
output
Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.
Try accessing using ?. instead.
  print(middleName.length);
                   ^^^^^^

Compare this with section 4: same mistake, but now Dart stops it before running.


11. A First Look at Nullable Variables

A type with ? is called nullable. A nullable variable can hold a real value or null, and can change between them. Printing it is always safe:

dart
void main() {
  String? middleName;
  print(middleName);
  middleName = 'Kamal';
  print(middleName);
}
output
null
Kamal

A nullable variable that is declared without a value starts as null — there is no error like the one in section 9. Declaring and using nullable types is the whole of the next lecture, Lecture 013.


12. The Road Ahead

You now know the problem and Dart's rule. The rest of Category 3 gives you the tools to work with values that might be missing:

LectureWhat it teaches
013 — Nullable & Non-Nullable Typesdeclaring String?, int?, and friends, and the rules between them
014 — Null-Aware Operators??, ?., and more: use a value or a fallback
015 — Null Assertion Operator !telling Dart "this is not null" — and the risk
016 — Null Safety in Real Codeputting it all together

Checking for null with an if statement comes in Lecture 022.


13. A Real-World Example

A sign-up form for Zayan. His name and age are required; his middle name and his referral code are optional and were left blank. The age arrives as text, as in Lecture 010:

dart
void main() {
  String name = 'Zayan';
  int age = int.parse('6');
  String? middleName;
  int? referralCode = int.tryParse('');

  print('Name: $name (${name.length} letters)');
  print('Age next year: ${age + 1}');
  print('Middle name: $middleName');
  print('Referral code: $referralCode');
}
output
Name: Zayan (5 letters)
Age next year: 7
Middle name: null
Referral code: null

name and age are non-nullable, so Dart lets us use length and + freely. middleName and referralCode are nullable, so we only print them. int.tryParse('') returns null because empty text is not a number.


Code Examples

Example 1 — Printing null

dart
void main() {
  print(null);
  print('Value: ${null}');
}
output
null
Value: null

Example 2 — null and Its Type

dart
void main() {
  print(null.runtimeType);
  print(null is Object);
  print('Ali' is Object);
}
output
Null
false
true

Example 3 — tryParse Produces null

dart
void main() {
  print(int.tryParse('15'));
  print(int.tryParse('fifteen'));
  print(double.tryParse('2.5'));
  print(double.tryParse('two'));
}
output
15
null
2.5
null

Example 4 — Non-Nullable Values Are Safe to Use

dart
void main() {
  String city = 'Lahore';
  int year = 2026;
  print(city.toUpperCase());
  print(year + 1);
}
output
LAHORE
2027

Example 5 — An Inferred Nullable Type

dart
void main() {
  var score = int.tryParse('88');
  print(score);
  print(score.runtimeType);
}
output
88
int

How it works

  1. int.tryParse might return null, so Dart infers score's type as int?.
  2. runtimeType reports the value, as in Lecture 010 — here a real int.
  3. Even though the value is 88, Dart still refuses score + 1: the type says it might be null.

Example 6 — A Nullable Variable Changing

dart
void main() {
  String? nickname;
  print(nickname);
  nickname = 'Zee';
  print(nickname);
}
output
null
Zee

Example 7 — Student Marks

dart
void main() {
  String student = 'Ali';
  int math = 80;
  int science = 75;
  int? english = int.tryParse('absent');

  print('Student: $student');
  print('Total: ${math + science}');
  print('English: $english');
}
output
Student: Ali
Total: 155
English: null

How it works

  1. math and science are non-nullable, so adding them is allowed.
  2. Ali was absent for English, so the mark text is not a number and english is null.
  3. We print english but do not add it — Dart would refuse, because it might be missing.

Example 8 — Shopping Total

dart
void main() {
  String product = 'Notebook';
  int price = 500;
  int quantity = 3;
  String? couponCode;

  print('Product: $product');
  print('Total: ${price * quantity}');
  print('Coupon: $couponCode');
}
output
Product: Notebook
Total: 1500
Coupon: null

How it works

  1. A product, price, and quantity are always known, so they are non-nullable.
  2. A coupon is optional. couponCode is String? and starts as null.
  3. Giving a nicer message than null — such as "none" — is the job of Lecture 014.

Example 9 — Bank Balance

dart
void main() {
  String owner = 'Sara';
  double balance = 1000.0;
  double? deposit = double.tryParse('250.5');
  double? withdrawal = double.tryParse('');

  print('Owner: $owner');
  print('Balance: $balance');
  print('Deposit: $deposit');
  print('Withdrawal: $withdrawal');
}
output
Owner: Sara
Balance: 1000.0
Deposit: 250.5
Withdrawal: null

How it works

  1. balance is a plain double: an account always has a balance.
  2. The deposit and withdrawal come from text boxes, so tryParse gives double?.
  3. The withdrawal box was empty, so withdrawal is null.

Example 10 — Temperature Reading

dart
void main() {
  double yesterday = 31.5;
  double? today = double.tryParse('--');

  print('Yesterday: $yesterday');
  print('Yesterday in Fahrenheit: ${yesterday * 9 / 5 + 32}');
  print('Today: $today');
}
output
Yesterday: 31.5
Yesterday in Fahrenheit: 88.7
Today: null

How it works

  1. yesterday is non-nullable, so the conversion formula is allowed.
  2. The sensor sent '--' today, which is not a number, so today is null.
  3. Converting today would need a way to deal with the missing value first — that is what Lectures 013–016 teach.

Common Beginner Mistakes

1. Assigning null to a non-nullable type

dart
void main() {
  // String name = null; // ✗
}
output
Error: A value of type 'Null' can't be assigned to a variable of type 'String'.

If a value may be missing, the type must say so: String? name;.

2. Expecting Object to accept null

dart
void main() {
  // Object item = null; // ✗
}
output
Error: A value of type 'Null' can't be assigned to a variable of type 'Object'.

Object means "any real value". null is not a real value.

3. Doing arithmetic on a tryParse result

dart
void main() {
  var age = int.tryParse('20');
  // print(age + 1); // ✗
}
output
Error: Operator '+' cannot be called on 'int?' because it is potentially null.

When the text is always a valid number, use int.parse, which gives an int. Working with an int? safely comes in Lectures 013–016.

4. Using a property of a nullable variable

dart
void main() {
  String? middleName;
  // print(middleName.length); // ✗
}
output
Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.

The type says the value might be missing — here it really is — so Dart refuses to ask for its length.

5. Using dynamic to get around null safety

dart
void main() {
  dynamic name = null;
  // print(name.length); // ✗ compiles, then crashes
}
output
Unhandled exception:
NoSuchMethodError: The getter 'length' was called on null.

dynamic switches off null safety along with every other check. The crash from before null safety comes right back.


Best Practices

  • Keep types non-nullable by default. Most values in a program are never missing.
  • Use a nullable type only when "no value" is a real, meaningful answer — an optional field, a failed tryParse.
  • Use int.parse when text is always a number, and int.tryParse when it might not be.
  • Don't use dynamic to make a null-safety error disappear; it only turns it into a crash.
  • Read Dart's error messages closely: "potentially null" means the type has a ?.

Mini Challenge

Sara enters her details in a library app. Her name 'Sara' and her number of borrowed books 2 are always known. Her phone number was left blank, and her membership number was typed as 'A12', which is not a number. Store the phone number as String? and parse the membership number with int.tryParse. Print everything.

Your program should print exactly:

output
Member: Sara
Books after one more: 3
Phone: null
Membership: null

Try it yourself before opening the solution.

Show solution
dart
void main() {
  String member = 'Sara';
  int books = 2;
  String? phone;
  int? membership = int.tryParse('A12');

  print('Member: $member');
  print('Books after one more: ${books + 1}');
  print('Phone: $phone');
  print('Membership: $membership');
}
output
Member: Sara
Books after one more: 3
Phone: null
Membership: null

How it works

  1. member and books are non-nullable, so books + 1 is allowed.
  2. phone is declared as String? with no value, so it starts as null.
  3. 'A12' is not a whole number, so int.tryParse returns null.

Practice Questions

Work through these in order — they run from beginner to application to challenge. Every question gives you exact values, so you can compare your output with the answers.

Beginner

  1. Print null, then print the runtimeType of null.
  2. Print the result of int.tryParse('7') and of int.tryParse('seven'), each on its own line.
  3. Print whether null is an Object and whether 0 is an Object, one result per line.

Application

  1. Declare String? nickname;, print it, then assign 'Ali' and print it again.

  2. This program does not compile. Fix it by adding one character, so that it prints null:

    dart
    void main() {
      String middleName = null;
      print(middleName);
    }
  3. Store price = 300 and quantity = 4 as int, and a String? gift message with no value. Print Total: 1200 and Gift message: null.

  4. Predict which of these three lines Dart rejects, and why. Then check by uncommenting each one in turn.

    dart
    void main() {
      var a = int.tryParse('10');
      int b = int.parse('10');
      // print(a + 1);
      // print(b + 1);
      // print(a);
    }
  5. Use double.tryParse to read Zayan's height from the text '3.9' and his weight from the text 'unknown'. Print Height: 3.9 and Weight: null.

Challenge

  1. This program compiles but crashes. Explain in one sentence why, then fix it by changing one word so that Dart catches the problem before the program runs. (Your fixed program should show a compile-time error.)

    dart
    void main() {
      dynamic city = null;
      print(city.length);
    }
  2. A weather app reads three temperatures from text: '28.5', 'n/a', and '30'. Read each with double.tryParse into its own variable and print them, one per line. Then explain in one sentence why Dart would refuse to add the three variables together.


Practice Answers

Question 1 — Solution

dart
void main() {
  print(null);
  print(null.runtimeType);
}
output
null
Null

Question 2 — Solution

dart
void main() {
  print(int.tryParse('7'));
  print(int.tryParse('seven'));
}
output
7
null

Question 3 — Solution

dart
void main() {
  print(null is Object);
  print(0 is Object);
}
output
false
true

Question 4 — Solution

dart
void main() {
  String? nickname;
  print(nickname);
  nickname = 'Ali';
  print(nickname);
}
output
null
Ali

Question 5 — Solution

Add ? after String, so the type allows null:

dart
void main() {
  String? middleName = null;
  print(middleName);
}
output
null

Writing String? middleName; gives the same result, because a nullable variable without a value starts as null. Your editor may even suggest it: "Redundant initialization to 'null'". Both versions are correct; the shorter one is the usual style.

Question 6 — Solution

dart
void main() {
  int price = 300;
  int quantity = 4;
  String? giftMessage;
  print('Total: ${price * quantity}');
  print('Gift message: $giftMessage');
}
output
Total: 1200
Gift message: null

Question 7 — Solution

Only print(a + 1); is rejected. a comes from tryParse, so its type is int?, and + cannot be used on a value that might be null. b comes from int.parse, so it is a plain int. Printing a is always allowed.

output
Error: Operator '+' cannot be called on 'int?' because it is potentially null.

With that line left commented out and the other two uncommented, the program prints:

output
11
10

Question 8 — Solution

dart
void main() {
  var height = double.tryParse('3.9');
  var weight = double.tryParse('unknown');
  print('Height: $height');
  print('Weight: $weight');
}
output
Height: 3.9
Weight: null

Question 9 — Solution

It crashes because city holds null, which has no length, and dynamic switched off the check that would have caught it. Change dynamic to String:

dart
void main() {
  String city = null;
  print(city.length);
}
output
Error: A value of type 'Null' can't be assigned to a variable of type 'String'.
  String city = null;
                ^

Now the mistake is reported before anything runs — a missing city is caught at the line that creates it, not halfway through the program.

Question 10 — Solution

dart
void main() {
  var morning = double.tryParse('28.5');
  var noon = double.tryParse('n/a');
  var evening = double.tryParse('30');
  print(morning);
  print(noon);
  print(evening);
}
output
28.5
null
30.0

All three variables are double?, because tryParse might fail — and here it really did for noon. Dart refuses + on a value that might be null. '30' prints as 30.0 because double.tryParse always gives a double.


Quick Revision

  1. What does null mean?
  2. What is the type of null?
  3. Is null an Object?
  4. What crash did null cause before null safety?
  5. Can a String variable hold null in Dart 3.12.2?
  6. How do you read the type int??
  7. Why does a String variable need a value before it is read?
  8. Why does dynamic bring back the old crash?

Key Takeaways

  • null means "no value here". It is the only value of the type Null.
  • null is not an Object, so an Object variable cannot hold it; dynamic can.
  • Using null as if it were a real value crashes the program while it runs.
  • Null safety means a variable can hold null only if its type says so.
  • String, int, double, bool, and Object are non-nullable — that is the default.
  • A ? after a type, as in int?, means "this type or null".
  • Dart refuses to use a possibly-null value, turning run-time crashes into compile-time errors.
  • The rules for reading variables (Lecture 004) and late (Lecture 006) exist because of null safety.

What's Next?

Lecture 013 — Nullable & Non-Nullable Types. You have seen the ? in error messages and a first nullable variable. Next we learn to declare nullable types on purpose, what Dart allows you to do with them, how values move between String and String?, and how to decide which one each variable should be.


Video lecture

Subscribe
Placeholder video — the real recording isn't linked yet.