On this page25 sections
- Prerequisites
- Connection With Previous Lectures
- Learning Objectives
- 1. What Is null?
- 2. Where null Comes From
- 3. null Has Its Own Type
- 4. The Problem: Using a Value That Isn't There
- 5. What Null Safety Means
- 6. Your Types Do Not Allow null
- 7. A Guarantee You Can Trust
- 8. Object Doesn't Allow null Either
- 9. Why Lectures 004 and 006 Had Their Rules
- 10. Types That Say "Or Null": ?
- 11. A First Look at Nullable Variables
- 12. The Road Ahead
- 13. A Real-World Example
- Code Examples
- Common Beginner Mistakes
- Best Practices
- Mini Challenge
- Practice Questions
- Practice Answers
- Quick Revision
- Key Takeaways
- What's Next?
Lecture 12 — Introduction to Null Safety
| Category | 3 — Null Safety |
| Lecture | 012 of 140 |
| Estimated video length | 10 min |
| Target | Dart 3.12.2 |
| Level | Beginner |
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)
lateas a promise that a value comes later (Lecture 006)runtimeType,is, andint.tryParsereturningnull(Lecture 010)- the difference between
Objectanddynamic, 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:
var age = int.tryParse('twenty'); // nullAnd 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
nullmeans and where it comes from - Recognize
nullas the only value of the typeNull - Describe the crash that
nullcauses when it is used by mistake - Explain what null safety means in Dart
- Recognize that
String,int,double, andboolcannot holdnull - Read the
?in a type such asint?as "or null" - Connect the rules from Lectures 004 and 006 to null safety
- Recognize the error messages Dart produces when
nullis 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:
void main() {
print(null);
}null2. 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:
void main() {
var good = int.tryParse('42');
var bad = int.tryParse('forty-two');
print(good);
print(bad);
}42
nullbad 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:
void main() {
print(null.runtimeType);
print(null is Object);
}Null
falseThe 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:
void main() {
dynamic name = null;
print(name.length);
}Unhandled exception:
NoSuchMethodError: The getter 'length' was called on null.
Receiver: null
Tried calling: lengthYou 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
nullonly 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.
void main() {
String name = null;
print(name);
}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.
void main() {
String name = 'Sara';
int age = 18;
print(name.length);
print(age + 1);
}4
19name.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:
void main() {
Object item = null;
print(item);
}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:
void main() {
String name;
print(name);
}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:
String name;
void main() {
print(name);
}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:
void main() {
var age = int.tryParse('20');
print(age + 1);
}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:
void main() {
String? middleName;
print(middleName.length);
}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:
void main() {
String? middleName;
print(middleName);
middleName = 'Kamal';
print(middleName);
}null
KamalA 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:
| Lecture | What it teaches |
|---|---|
| 013 — Nullable & Non-Nullable Types | declaring 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 Code | putting 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:
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');
}Name: Zayan (5 letters)
Age next year: 7
Middle name: null
Referral code: nullname 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
void main() {
print(null);
print('Value: ${null}');
}null
Value: nullExample 2 — null and Its Type
void main() {
print(null.runtimeType);
print(null is Object);
print('Ali' is Object);
}Null
false
trueExample 3 — tryParse Produces null
void main() {
print(int.tryParse('15'));
print(int.tryParse('fifteen'));
print(double.tryParse('2.5'));
print(double.tryParse('two'));
}15
null
2.5
nullExample 4 — Non-Nullable Values Are Safe to Use
void main() {
String city = 'Lahore';
int year = 2026;
print(city.toUpperCase());
print(year + 1);
}LAHORE
2027Example 5 — An Inferred Nullable Type
void main() {
var score = int.tryParse('88');
print(score);
print(score.runtimeType);
}88
intHow it works
int.tryParsemight returnnull, so Dart infersscore's type asint?.runtimeTypereports the value, as in Lecture 010 — here a realint.- Even though the value is
88, Dart still refusesscore + 1: the type says it might benull.
Example 6 — A Nullable Variable Changing
void main() {
String? nickname;
print(nickname);
nickname = 'Zee';
print(nickname);
}null
ZeeExample 7 — Student Marks
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');
}Student: Ali
Total: 155
English: nullHow it works
mathandscienceare non-nullable, so adding them is allowed.- Ali was absent for English, so the mark text is not a number and
englishisnull. - We print
englishbut do not add it — Dart would refuse, because it might be missing.
Example 8 — Shopping Total
void main() {
String product = 'Notebook';
int price = 500;
int quantity = 3;
String? couponCode;
print('Product: $product');
print('Total: ${price * quantity}');
print('Coupon: $couponCode');
}Product: Notebook
Total: 1500
Coupon: nullHow it works
- A product, price, and quantity are always known, so they are non-nullable.
- A coupon is optional.
couponCodeisString?and starts asnull. - Giving a nicer message than
null— such as "none" — is the job of Lecture 014.
Example 9 — Bank Balance
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');
}Owner: Sara
Balance: 1000.0
Deposit: 250.5
Withdrawal: nullHow it works
balanceis a plaindouble: an account always has a balance.- The deposit and withdrawal come from text boxes, so
tryParsegivesdouble?. - The withdrawal box was empty, so
withdrawalisnull.
Example 10 — Temperature Reading
void main() {
double yesterday = 31.5;
double? today = double.tryParse('--');
print('Yesterday: $yesterday');
print('Yesterday in Fahrenheit: ${yesterday * 9 / 5 + 32}');
print('Today: $today');
}Yesterday: 31.5
Yesterday in Fahrenheit: 88.7
Today: nullHow it works
yesterdayis non-nullable, so the conversion formula is allowed.- The sensor sent
'--'today, which is not a number, sotodayisnull. - Converting
todaywould 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
void main() {
// String name = null; // ✗
}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
void main() {
// Object item = null; // ✗
}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
void main() {
var age = int.tryParse('20');
// print(age + 1); // ✗
}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
void main() {
String? middleName;
// print(middleName.length); // ✗
}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
void main() {
dynamic name = null;
// print(name.length); // ✗ compiles, then crashes
}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.parsewhen text is always a number, andint.tryParsewhen it might not be. - Don't use
dynamicto 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:
Member: Sara
Books after one more: 3
Phone: null
Membership: nullTry it yourself before opening the solution.
Show solution
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');
}Member: Sara
Books after one more: 3
Phone: null
Membership: nullHow it works
memberandbooksare non-nullable, sobooks + 1is allowed.phoneis declared asString?with no value, so it starts asnull.'A12'is not a whole number, soint.tryParsereturnsnull.
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
- Print
null, then print theruntimeTypeofnull. - Print the result of
int.tryParse('7')and ofint.tryParse('seven'), each on its own line. - Print whether
nullis anObjectand whether0is anObject, one result per line.
Application
-
Declare
String? nickname;, print it, then assign'Ali'and print it again. -
This program does not compile. Fix it by adding one character, so that it prints
null:void main() { String middleName = null; print(middleName); } -
Store
price = 300andquantity = 4asint, and aString?gift message with no value. PrintTotal: 1200andGift message: null. -
Predict which of these three lines Dart rejects, and why. Then check by uncommenting each one in turn.
void main() { var a = int.tryParse('10'); int b = int.parse('10'); // print(a + 1); // print(b + 1); // print(a); } -
Use
double.tryParseto read Zayan's height from the text'3.9'and his weight from the text'unknown'. PrintHeight: 3.9andWeight: null.
Challenge
-
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.)
void main() { dynamic city = null; print(city.length); } -
A weather app reads three temperatures from text:
'28.5','n/a', and'30'. Read each withdouble.tryParseinto 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
void main() {
print(null);
print(null.runtimeType);
}null
NullQuestion 2 — Solution
void main() {
print(int.tryParse('7'));
print(int.tryParse('seven'));
}7
nullQuestion 3 — Solution
void main() {
print(null is Object);
print(0 is Object);
}false
trueQuestion 4 — Solution
void main() {
String? nickname;
print(nickname);
nickname = 'Ali';
print(nickname);
}null
AliQuestion 5 — Solution
Add ? after String, so the type allows null:
void main() {
String? middleName = null;
print(middleName);
}nullWriting 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
void main() {
int price = 300;
int quantity = 4;
String? giftMessage;
print('Total: ${price * quantity}');
print('Gift message: $giftMessage');
}Total: 1200
Gift message: nullQuestion 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.
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:
11
10Question 8 — Solution
void main() {
var height = double.tryParse('3.9');
var weight = double.tryParse('unknown');
print('Height: $height');
print('Weight: $weight');
}Height: 3.9
Weight: nullQuestion 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:
void main() {
String city = null;
print(city.length);
}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
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);
}28.5
null
30.0All 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
- What does
nullmean? - What is the type of
null? - Is
nullanObject? - What crash did
nullcause before null safety? - Can a
Stringvariable holdnullin Dart 3.12.2? - How do you read the type
int?? - Why does a
Stringvariable need a value before it is read? - Why does
dynamicbring back the old crash?
Key Takeaways
nullmeans "no value here". It is the only value of the typeNull.nullis not anObject, so anObjectvariable cannot hold it;dynamiccan.- Using
nullas if it were a real value crashes the program while it runs. - Null safety means a variable can hold
nullonly if its type says so. String,int,double,bool, andObjectare non-nullable — that is the default.- A
?after a type, as inint?, means "this type ornull". - Dart refuses to use a possibly-
nullvalue, 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.