Object Oriented Dart & Flutter. Koans way.

Aleksey Drobnych
5 min readJun 8, 2020

--

Classes and Objects

After tasting the basics of Dart with koans here and here, let’s play with Dart’s perfect implementation of Object-Oriented Programming (OOP).

OOP is one of the Great Ideas in IT. Before its invention, programmers used very primitive computer languages. Procedures were the sole building blocks of any program. OOP introduced classes and objects to reflect things of the real world inside the code. The change was so dramatic, so you can compare the old (procedural) and new (object-oriented) languages as vocabularies of prehistoric people communicating with gestures and verbs and, say, today’s English.

Indeed, you can read the next code example as near some prose:

first OOP program

Don’t worry if you don’t get immediately how this code works. We’ll go step by step. We’ll use FlutLab in our experiments.

Why OOP is important for Flutter developers? Because widgets are classes also! If you will get how OOP works, you will understand why and where to use proper language. For example, when to say “extends”, when “with” and so on. And you will be able to create your own widgets also!

How it works

Your object-oriented code will always start with the class keyword. With this word, you introducing a new concept of real life to the code of your program.

In the above example you explaining: look, in my world, there is a thing, named Person. This thing can have a name, a gender and an age. And it can introduce itself if you will ask a bio action from it.

So, the class is a definition, a type that you can use later in your program.

The second step of your object-oriented code is the creation of an object using a class as its definition:

Person john = Person(name: 'John', gender: Gender.male, age: 20);

After this moment, you can use john as any other variable in your program, getting and setting its state, invoking actions, and sending it as a function parameter whenever needed.

Try the code

Go to FlutLab, login and pick some project. Go to test folder and open widget_test.dart:

place for our experiments

Copy & paste this code instead of current content of widget_test.dart:

import 'package:flutter_test/flutter_test.dart';const ___ = "FILL ME IN";class Gender {  static const female = "woman";  static const male = "man";}class Person {  String name;  String gender;  int age;  Person({this.name, this.gender, this.age});  String bio() {    return "My name is $name. I'm a $age years old $gender";  }}void main() {  test('Object creation', () {      Person john = Person(name: 'John', gender: Gender.male, age: 20);      expect('My name is John. I\'m a 20 years old man', john.bio());  });}

Run unit test with this icon-button from the top menu:

run it!

Wait until build finished and observe Green Test:

Unit tests passed successfully, Koan is Green

If you will compare this example with the previous Dart koans, you will find that we jumped immediately to the last, Green state. This was done intentionally. Koan is a playground. We will start with the passed unit test here and will modify the code to understand Dart’s OOP more deeply.

What’s inside a class?

Our Person class consists of 3 parts:

  • fields (name, gender, age)
  • constructor (Person(…))
  • methods (bio)

Methods are functions defined inside a class. The special word “method” reflects the shift out of old terminology, where functions and procedures were the sole building bricks of a code.

OOP introduces an important distinction between fields and methods:

  • field describes the state of an object (name, speed, size, etc.)
  • method describes the behavior of an object (ability to run, talk, do something)

Where is a constructor in this schema?

It’s a special method, which is automatically invoked when we’re creating a new object. Usually, constructors set up the initial state of the object.

How our program can look like without a constructor? In this case, we need to set up all the fields manually just after the creation of an “empty” object:

Green test after the modification

As you can see, we have not to forget to set up a single field! It’s a very brittle solution. That’s why constructors are so useful! You can have as many constructors for the same class a needed, setting the objects in various flavors and specializations.

Let’s back our constructor back but in its generic form, without syntactic sugar:

Green test after the modification

Do you see how we differentiate fields from the parameters with the same name? We use this — the reserved word which objects use to refer to their selves.

Now you see the main job of the constructor without any magic — it should set all the fields before the first use of the newly created object.

Another experiment: let’s try to remove those strange internal curly brackets. But the test immediately fails!

Red Koan after the modification

And the error is “Too few positional arguments: 3 required, 0 given.”

Curly brackets in Dart gives a very important feature to any constructor and any method: named parameters.

Just again how convenient we can feed parameters into the Person constructor:

Person(name: 'John', gender: Gender.male, age: 20)

Without curly brackets, you have to remember the exact sequence of parameters and provide them without any hints:

Person('John', Gender.male, 20)

Let’s fix our last failing Koan with this another form of sending parameters:

Koan is Green again!

Final notes

The creation of an object is the most popular way to use classes. But not the sole one. In some cases, we can introduce “abstract” truth, or value, not related to some specific object, but to the class in general.

Look at our second class, Gender.

What do we want to say by this class declaration? We want to say that there are only two special values, linked to the entity “Gender”: female and male.

We defined them as class fields but with the prefix “static”. This means that those fields belong not to an object, but to the class itself!

So now you can get why we did not create the objects from Gender class and used its own fields instead:

Gender.male

Conclusion

There was just starting a discussion about Dart’s implementation of OOP. Stay tuned, the story has its continuation.

--

--