Let's think about it this way for a sec
This lesson brings together the null safety, OOP (classes, constructors, inheritance, mixins), and Future/async/await concepts from the Intermediate/Advanced chapter into some tougher practice tasks. In real app development, you rarely use these concepts in isolation — they're almost always combined. So these exercises give you practice handling nullable fields within a class hierarchy and returning objects from async functions. Once you've written your solution, check where null safety errors (`!`, `?`, `??`) could still crop up.
Exercises
Task 1: Build an `Animal` base class with a name (String) field and a nullable `sound` (String?) field. Write a `makeSound()` method that prints "..." when sound is null, and uses the null-aware operator (`??`) to print the sound when it's not null. Task 2: Create a `Dog` class that inherits from `Animal`, calling `super` in its constructor and defaulting sound to "Woof". Task 3: Build a `Flyable` mixin with a `fly()` method, then have a `Bird` class extend `Animal` and use `with Flyable`. Task 4: Write an async function `Future<Animal> fetchRandomAnimal()` that waits 1 second via `Future.delayed` and then returns a `Dog` object — call it with `await` inside `main()` and then call `makeSound()`.
Code Example
class Animal {
String name;
String? sound;
Animal(this.name, [this.sound]);
void makeSound() {
// TODO: use ?? to handle null sound
print('$name says ${sound ?? "..."}');
}
}
class Dog extends Animal {
Dog(String name) : super(name, 'Woof');
}
mixin Flyable {
void fly() => print('Flying...');
}
class Bird extends Animal with Flyable {
Bird(String name) : super(name, 'Tweet');
}
Future<Animal> fetchRandomAnimal() async {
await Future.delayed(Duration(seconds: 1));
return Dog('Rex');
}
void main() async {
final cat = Animal('Cat');
cat.makeSound();
final dog = Dog('Buddy');
dog.makeSound();
final bird = Bird('Sky');
bird.makeSound();
bird.fly();
print('Fetching...');
final randomAnimal = await fetchRandomAnimal();
randomAnimal.makeSound();
}Your console should print, in order: Cat ('...'), Buddy ('Woof'), Sky ('Tweet' + 'Flying...'), and then — after a 1-second wait — Rex ('Woof').Try It in 5 Minutes
Set a 5-minute timer, create a new `Cat` class that inherits from `Animal` (without the `Flyable` mixin), default sound to null, and call `makeSound()`.
A Quick Heads-Up
When inheriting from a class with a nullable field, don't forget to add an extra null check in the subclass — even if the base class shouldn't leave it null, defensive coding is still a good habit.