Thuta Learning
ExercisesProgrammingbeginner

Dart Exercises: OOP and Async

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Practice Dart Exercises: OOP and Async hands-on, on your own
  • Reinforce the skills you've already learned through practice
  • Learn to find and fix your own mistakes, and check your own work

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

dart
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();
}
You should see
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.

Easy traps

  • Getting the positional parameter order wrong in `super(name, 'Woof')`, which triggers a constructor error
  • Using an async function's return value directly without `await`, which causes a `Future<Animal>` type mismatch error

Now Try It Yourself

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()`.

You'll know it worked when: Your console should print, in order: Cat ('...'), Buddy ('Woof'), Sky ('Tweet' + 'Flying...'), and then — after a 1-second wait — Rex ('Woof').

Dart Exercises: OOP and Async | Thuta Learning