Nullable vs Non-Nullable
Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 24 of 110.
Now that you understand why null safety matters, let's look at how to declare variables that can hold null. In Dart, you make a type nullable by adding a ? after the type name.
String name = 'Alice'; // Non-nullable - must always have a value
String? nickname; // Nullable - can be null or a String
print(name); // Alice
print(nickname); // nullThe key difference is that non-nullable types guarantee a value exists, while nullable types explicitly allow the absence of a value. This distinction applies to all types:
int count = 10; // Must have a value
int? optionalCount; // Can be null
List<String> items = []; // Must be a list (can be empty)
List<String>? maybeItems; // Could be null (no list at all)Notice that an empty list [] is different from null. An empty list exists but contains nothing; null means no list exists at all.
The compiler enforces these rules strictly. You cannot assign null to a non-nullable variable, and you cannot use a nullable variable where a non-nullable one is expected without first checking for null:
String? maybeName = 'Bob';
// String definite = maybeName; // Error! Can't assign nullable to non-nullableIn the next lesson, you'll learn the operators Dart provides to safely work with nullable values.
Challenge
EasyLet's build a movie watchlist system that demonstrates the difference between required information and optional information using nullable and non-nullable types.
You'll create two files to organize your code:
movie.dart: Define aMovieclass that represents a film in your watchlist. Every movie must have a title and release year (these are always required), but some additional details might not be available for every movie. Your class should have:- A non-nullable
String title- every movie must have a title - A non-nullable
int year- every movie must have a release year - A nullable
String? director- the director might be unknown - A nullable
double? rating- not all movies have been rated yet - A constructor that takes
titleandyearas required parameters - A
displayInfo()method that prints the movie's information, showingUnknownfor missing director andNot ratedfor missing rating
- A non-nullable
main.dart: Import your movie class and create a small watchlist demonstrating both complete and incomplete movie data:- Create a movie with title
'Inception'and year2010, then set its director to'Christopher Nolan'and rating to8.8 - Create a movie with title
'The Matrix'and year1999, then set only its rating to8.7(leave director as null) - Create a movie with title
'Upcoming Film'and year2025(leave both director and rating as null) - Call
displayInfo()on each movie in the order listed above
- Create a movie with title
The displayInfo() method should print in this exact format:
[title] ([year])
Director: [director or "Unknown"]
Rating: [rating or "Not rated"]Notice how the non-nullable fields (title and year) are always guaranteed to have values, while the nullable fields (director? and rating?) can remain unset. This reflects real-world scenarios where some data is essential and some is optional.
Expected output:
Inception (2010)
Director: Christopher Nolan
Rating: 8.8
The Matrix (1999)
Director: Unknown
Rating: 8.7
Upcoming Film (2025)
Director: Unknown
Rating: Not ratedCheat sheet
To make a type nullable in Dart, add a ? after the type name:
String name = 'Alice'; // Non-nullable - must always have a value
String? nickname; // Nullable - can be null or a StringThis distinction applies to all types:
int count = 10; // Must have a value
int? optionalCount; // Can be null
List<String> items = []; // Must be a list (can be empty)
List<String>? maybeItems; // Could be null (no list at all)An empty list [] is different from null. An empty list exists but contains nothing; null means no list exists at all.
The compiler enforces null safety rules strictly. You cannot assign null to a non-nullable variable, and you cannot use a nullable variable where a non-nullable one is expected without first checking for null:
String? maybeName = 'Bob';
// String definite = maybeName; // Error! Can't assign nullable to non-nullableTry it yourself
import 'movie.dart';
void main() {
// TODO: Create a movie with title 'Inception' and year 2010
// Then set its director to 'Christopher Nolan' and rating to 8.8
// TODO: Create a movie with title 'The Matrix' and year 1999
// Then set only its rating to 8.7 (leave director as null)
// TODO: Create a movie with title 'Upcoming Film' and year 2025
// Leave both director and rating as null
// TODO: Call displayInfo() on each movie in order
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesLibraries & ImportsIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsInstance VariablesConstructor BasicsRecap - Simple Calculator4Null Safety
Intro to Null SafetyNullable vs Non-NullableThe ? and ! OperatorsLate Keyword & Null SafetyNull-Aware OperatorsNull Safety in ClassesRecap - User Profile System7Abstract Classes & Interfaces
Abstract ClassesAbstract MethodsInterfaces in DartImplicit InterfacesImplementing vs ExtendingMultiple InterfacesRecap - Shape Calculator10Collections & Generics
List, Set, Map OverviewType-Safe CollectionsGeneric ClassesGeneric MethodsGeneric ConstraintsIterable & IteratorRecap - Generic Storage13Advanced OOP Concepts
Composition vs InheritanceExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums with Methods16Project: Library Management
Project OverviewBook and User Classes2Constructors in Dart
Default ConstructorNamed ConstructorsInitializer ListsConstant ConstructorsFactory ConstructorsRedirecting ConstructorsRecap - Shape Builder5Encapsulation
Public vs Private MembersThe _ Prefix ConventionLibrary-Level PrivacyGetters & Setters DepthInformation HidingRecap - Student Records8Mixins
Introduction to MixinsCreating MixinsUsing Multiple Mixinson Keyword in MixinsMixin vs InheritanceMixin vs InterfaceRecap - Animal System11Special Methods
toString() OverridehashCode & == OverrideComparable Interfacecall() MethodnoSuchMethod OverrideRecap - Custom Collection14Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern3Class Properties
Instance vs Static MembersFinal & Const FieldsLate VariablesStatic Methods & FieldsGetters and SettersRecap - Bank Account Manager6Inheritance
Basic InheritanceThe super KeywordMethod OverridingThe @override AnnotationThe final Class KeywordConstructors & InheritanceRecap - Employee Hierarchy9Polymorphism
Polymorphism BasicsPolymorphism via InterfacesRuntime Type CheckingThe is & as OperatorsCovariant KeywordRecap - Payment Processor