Watch the video (10 min)
On this page22 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. 1. You Have Been Using Objects All Along
  5. 2. State and Behaviour
  6. 3. A Class Is the Blueprint
  7. 4. Your First Class
  8. 5. Giving an Object Its Own Data
  9. 6. Adding Behaviour: a Method
  10. 7. A Method That Changes State
  11. 8. Why a Class Beats a Map
  12. 9. The Four Pillars of OOP
  13. 10. A Real-World Example
  14. Code Examples
  15. Common Beginner Mistakes
  16. Best Practices
  17. Mini Challenge
  18. Practice Questions
  19. Practice Answers
  20. Quick Revision
  21. Key Takeaways
  22. What's Next?

Lecture 52 — OOP Fundamentals

Category9 — Object-Oriented Programming
Lecture052 of 140
Estimated video length10 min
TargetDart 3.12.2
LevelBeginner

A map can hold a student's name and age, but Dart cannot check it: a misspelled key gives null and every value loses its type. A class describes the record once, and Dart checks every use of it.

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 001–051:

  • variables, types and naming conventions (Lectures 004–007)
  • that every value in Dart is an Object (Lecture 011)
  • functions with parameters and return values (Lectures 030–033)
  • lists, for-in loops and maps (Lectures 039–050)
  • records stored as List<Map<…>> (Lecture 051)

Connection With Previous Lectures

In Lecture 051 we stored records in maps. Here is a student:

dart
void main() {
  var ali = {'name': 'Ali', 'age': 20};
  print(ali['name']);
  print(ali['nmae']);
}
output
Ali
null

The typo 'nmae' is not an error — just a silent null. And because the map mixes a String and an int, Dart types every value as Object, so even simple arithmetic fails:

dart
void main() {
  var ali = {'name': 'Ali', 'age': 20};
  // print(ali['age'] + 1); // ✗ the value's type is Object?, not int
}
output
Error: The operator '+' isn't defined for the type 'Object?'.

We need a way to say "a student has a String name and an int age" — once — and have Dart check every use. That is what a class does.


Learning Objectives

By the end of this lecture you will be able to:

  • Explain what an object is, in terms of state and behaviour
  • Explain the difference between a class and an object
  • Write a small class with fields and a method
  • Create several objects from one class and change each one separately
  • Call a method on an object and explain which object's data it uses
  • Explain why a class is safer than a map for a record
  • Name the four pillars of object-oriented programming
  • Recognize the errors Dart gives for common class mistakes

1. You Have Been Using Objects All Along

An object is a value that bundles data with actions that work on that data. Every string and list you have used is one.

dart
void main() {
  var name = 'Sara';
  print(name.length);
  print(name.toUpperCase());

  var marks = [80, 75];
  marks.add(90);
  print(marks.length);
}
output
4
SARA
3

The string knows its own length and can make an uppercase copy. The list knows its elements and can add one. The dot . reaches into an object for its data or its actions.


2. State and Behaviour

Every object has two sides:

  • State — the data it holds right now (a list's elements, an account's balance).
  • Behaviour — what it can do (add an element, deposit money).
ThingStateBehaviour
Studentname, age, marksintroduce, calculate average
Bank accountowner, balancedeposit, withdraw
Shopping cartitems, pricesadd item, calculate total
Thermometertemperature in °Cconvert to °F

Object-oriented programming (OOP) is the habit of modelling a program as objects like these, each looking after its own state.


3. A Class Is the Blueprint

A class describes a kind of object: which data it holds and what it can do. An object created from a class is called an instance of it.

Analogy — a class is the architect's blueprint for a house; an object is a house built from it. One blueprint, many houses — and painting one house does not repaint the others.

String and List are classes written by the Dart team. 'Sara' is one instance of String, and runtimeType (Lecture 010) names the class of any value:

dart
void main() {
  print('Sara'.runtimeType);
  print([80, 75].runtimeType);
}
output
String
List<int>

Now we will write a class of our own.


4. Your First Class

A class is written with the keyword class, a name in UpperCamelCase, and a body in braces. Variables inside a class are called fields:

dart
class Student {
  String name = '';
  int age = 0;
}

void main() {
  var ali = Student();
  print(ali.name);
  print(ali.age);
}
output

0

Student() — the class name followed by () — creates a new object. The fields start with their default values, so name is the empty string (the blank first line) and age is 0. Classes are written at the top level, outside main().


5. Giving an Object Its Own Data

Use the dot to read and change an object's fields. Each object has its own copy of every field:

dart
class Student {
  String name = '';
  int age = 0;
}

void main() {
  var ali = Student();
  ali.name = 'Ali';
  ali.age = 20;

  var sara = Student();
  sara.name = 'Sara';
  sara.age = 18;

  print('${ali.name} is ${ali.age}');
  print('${sara.name} is ${sara.age}');
}
output
Ali is 20
Sara is 18

One class, two objects, two separate sets of data. Setting all fields one line at a time is clumsy; Lecture 054 — Constructors gives an object its values at the moment it is created.


6. Adding Behaviour: a Method

A function written inside a class is called a method. A method can use the object's fields directly by name:

dart
class Student {
  String name = '';
  int age = 0;

  void introduce() {
    print('Hi, I am $name and I am $age.');
  }
}

void main() {
  var ali = Student();
  ali.name = 'Ali';
  ali.age = 20;
  ali.introduce();
}
output
Hi, I am Ali and I am 20.

ali.introduce() runs the method for ali, so name inside it means ali.name.


7. A Method That Changes State

Methods can change the object's fields and return values, just like the functions of Lecture 030:

dart
class BankAccount {
  String owner = '';
  int balance = 0;

  void deposit(int amount) {
    balance = balance + amount;
  }

  bool canAfford(int price) {
    return balance >= price;
  }
}

void main() {
  var account = BankAccount();
  account.owner = 'Sara';
  account.deposit(500);
  account.deposit(250);
  print('${account.owner}: ${account.balance}');
  print(account.canAfford(1000));
}
output
Sara: 750
false

The data (balance) and the rules that change it (deposit) now live together. Anyone who wants to know how a balance changes looks in one place: the class.


8. Why a Class Beats a Map

Back to the problems from the start. With a class, a typo is a compile-time error instead of a silent null:

dart
class Student {
  String name = '';
  int age = 0;
}

void main() {
  var ali = Student();
  // print(ali.nmae); // ✗ there is no field called nmae
}
output
Error: The getter 'nmae' isn't defined for the type 'Student'.

Each field keeps its own type, so ali.age + 1 just works — and a wrong value is caught:

dart
class Student {
  String name = '';
  int age = 0;
}

void main() {
  var ali = Student();
  print(ali.age + 1);
  // ali.age = 'twenty'; // ✗ age is an int
}
output
1
output
Error: A value of type 'String' can't be assigned to a variable of type 'int'.
Map recordClass
Misspelled namesilent nullcompile-time error
Field typesone shared type (often Object)each field its own type
Behaviourseparate functionsmethods on the object
Required fieldsanyone can forget a keyevery object has every field

Maps are still the right choice for lookups by key (Lecture 051). For a record with fixed fields, use a class.


9. The Four Pillars of OOP

Object-oriented programming rests on four ideas. You only need their names today — each one has its own lectures:

PillarIdea in one sentenceStudied in
EncapsulationAn object protects its own data and lets others change it only through its methods.Lecture 057 — Private Members & Encapsulation
InheritanceA new class can build on an existing class and reuse what it has.Lecture 059 — Inheritance
PolymorphismDifferent objects can answer the same method call in their own way.Lecture 065 — Polymorphism
AbstractionCode depends on what an object can do, not how it does it.Lectures 062 — Abstract Classes and 063 — Interfaces

The BankAccount above already hints at encapsulation: deposit is the "proper" way to change balance. Right now nothing stops someone writing account.balance = 1000000; Lecture 057 shows how to forbid that.


10. A Real-World Example

A class with a list field and a method that calculates from it, used for several students:

dart
class Student {
  String name = '';
  List<int> marks = [];

  double average() {
    var total = 0;
    for (final mark in marks) {
      total += mark;
    }
    return total / marks.length;
  }
}

void main() {
  var ali = Student();
  ali.name = 'Ali';
  ali.marks = [80, 75, 85];

  var sara = Student();
  sara.name = 'Sara';
  sara.marks = [92, 88, 95];

  for (final student in [ali, sara]) {
    print('${student.name}: ${student.average()}');
  }
}
output
Ali: 80.0
Sara: 91.66666666666667

Compare Lecture 051's Map<String, List<int>>: the same data, but now each student is one typed object that can calculate its own average. A List<Student> holds them like any other value.


Code Examples

Example 1 — A Class with Two Fields

dart
class Book {
  String title = 'Untitled';
  int pages = 0;
}

void main() {
  var book = Book();
  print(book.title);
  print(book.pages);
}
output
Untitled
0

Example 2 — Changing Fields

dart
class Book {
  String title = 'Untitled';
  int pages = 0;
}

void main() {
  var book = Book();
  book.title = 'Dart Basics';
  book.pages = 240;
  print('${book.title}: ${book.pages} pages');
}
output
Dart Basics: 240 pages

Example 3 — Two Objects Are Independent

dart
class Counter {
  int count = 0;
}

void main() {
  var a = Counter();
  var b = Counter();
  a.count = 5;
  print(a.count);
  print(b.count);
}
output
5
0

Example 4 — A Method That Prints

dart
class Dog {
  String name = '';

  void bark() {
    print('$name says woof');
  }
}

void main() {
  var dog = Dog();
  dog.name = 'Rex';
  dog.bark();
}
output
Rex says woof

Example 5 — A Method That Returns a Value

dart
class Rectangle {
  double width = 0;
  double height = 0;

  double area() {
    return width * height;
  }
}

void main() {
  var room = Rectangle();
  room.width = 4;
  room.height = 3.5;
  print(room.area());
}
output
14.0

Example 6 — A Method That Changes a Field

dart
class Counter {
  int count = 0;

  void increment() {
    count++;
  }
}

void main() {
  var clicks = Counter();
  clicks.increment();
  clicks.increment();
  clicks.increment();
  print(clicks.count);
}
output
3

Example 7 — Student Report

dart
class Student {
  String name = '';
  int mark = 0;

  bool passed() {
    return mark >= 50;
  }
}

void main() {
  var zayan = Student();
  zayan.name = 'Zayan';
  zayan.mark = 64;
  print('${zayan.name} passed: ${zayan.passed()}');
}
output
Zayan passed: true

Example 8 — Shopping Cart

dart
class Cart {
  List<int> prices = [];

  void add(int price) {
    prices.add(price);
  }

  int total() {
    var sum = 0;
    for (final price in prices) {
      sum += price;
    }
    return sum;
  }
}

void main() {
  var cart = Cart();
  cart.add(120);
  cart.add(250);
  cart.add(90);
  print('Items: ${cart.prices.length}');
  print('Total: ${cart.total()}');
}
output
Items: 3
Total: 460

Example 9 — Bank Account

dart
class BankAccount {
  int balance = 0;

  void deposit(int amount) {
    balance += amount;
  }

  void withdraw(int amount) {
    if (amount <= balance) {
      balance -= amount;
    } else {
      print('Not enough money');
    }
  }
}

void main() {
  var account = BankAccount();
  account.deposit(1000);
  account.withdraw(300);
  account.withdraw(900);
  print('Balance: ${account.balance}');
}
output
Not enough money
Balance: 700

The rule "you cannot withdraw more than you have" lives inside the class, next to the data it protects.

Example 10 — Thermometer

dart
class Thermometer {
  double celsius = 0;

  double fahrenheit() {
    return celsius * 9 / 5 + 32;
  }
}

void main() {
  var lahore = Thermometer();
  lahore.celsius = 35;
  print('${lahore.celsius} °C = ${lahore.fahrenheit()} °F');
}
output
35.0 °C = 95.0 °F

Common Beginner Mistakes

1. Forgetting the parentheses

dart
class Student {
  String name = '';
}

void main() {
  var ali = Student; // no () — this is the class itself, not a new object
  // ali.name = 'Ali'; // ✗
}
output
Error: The setter 'name' isn't defined for the type 'Type'.

Student() creates an object; Student alone names the class.

2. A field without a starting value

dart
class Student {
  // String name; // ✗ a String cannot start as null
}
output
Error: Field 'name' should be initialized because its type 'String' doesn't allow null.

The same rule as top-level variables in Lecture 004. Give it a default for now; Lecture 054 shows how a constructor supplies the value instead.

3. Calling a method on the class instead of an object

dart
class Student {
  String name = '';

  void introduce() {
    print('Hi, I am $name');
  }
}

void main() {
  // Student.introduce(); // ✗ which student?
}
output
Error: Member not found: 'Student.introduce'.

Create an object first and call the method on it: Student().introduce().

4. Writing a class inside main()

dart
void main() {
  // class Student {} // ✗ classes live at the top level
}
output
Error: 'class' can't be used as an identifier because it's a keyword.

Inside a function, Dart reads class as an ordinary name and gets confused. Move the class outside main().

5. Misspelling a field name

ali.nmae gives Error: The getter 'nmae' isn't defined for the type 'Student'. — a good error: the same typo in a map would have given a silent null.


Best Practices

  • Name classes in UpperCamelCase (BankAccount) and fields and methods in lowerCamelCase (balance, deposit).
  • One class should describe one thing.
  • Name fields with nouns (balance) and methods with verbs (deposit, calculateTotal).
  • Put the rules that change a field in a method of the same class, not scattered in main().
  • Use a class for records with fixed fields, and a map for lookups by key.

Mini Challenge

Write a Player class with a name (default '') and a score (default 0), and a method addPoints(int points). Create Ali, give him 10 points and then 15 more, and print:

output
Ali: 25

Try it yourself before opening the solution.

Show solution
dart
class Player {
  String name = '';
  int score = 0;

  void addPoints(int points) {
    score += points;
  }
}

void main() {
  var ali = Player();
  ali.name = 'Ali';
  ali.addPoints(10);
  ali.addPoints(15);
  print('${ali.name}: ${ali.score}');
}
output
Ali: 25

Practice Questions

Beginner

  1. For a car, name two pieces of state and two behaviours.
  2. Write a class City with a field name (default ''). Create one, set its name to 'Lahore', and print it.
  3. Create two City objects named 'Lahore' and 'Karachi' and print both names.
  4. What does Student mean on its own, and what does Student() mean?

Application

  1. Write a class Circle with a double radius = 0 and a method double area() that returns 3.14 * radius * radius. Print the area for radius 10.
  2. Write a class Lamp with bool isOn = false and a method toggle() that flips it. Toggle a lamp three times and print isOn.
  3. Write a class Product with name and price, and a method int priceFor(int quantity). Create tea at 120 and print the price for 3.
  4. Name the four pillars of OOP and the lecture where each is studied.

Challenge

  1. Write a class Wallet with int balance = 0 and a method bool pay(int amount) that subtracts the amount and returns true only if there is enough money, otherwise returns false without changing anything. Deposit 500 by setting balance, then pay 200 and then 400, printing each result and the final balance.
  2. Write a class Student with a name and List<int> marks, and a method int highest(). Create Sara with marks [72, 95, 88] and print Sara: 95.

Practice Answers

Question 1 — Solution

State: colour, speed, fuel level. Behaviour: accelerate, brake, refuel. (Any two of each.)

Question 2 — Solution

dart
class City {
  String name = '';
}

void main() {
  var city = City();
  city.name = 'Lahore';
  print(city.name);
}
output
Lahore

Question 3 — Solution

dart
class City {
  String name = '';
}

void main() {
  var a = City();
  var b = City();
  a.name = 'Lahore';
  b.name = 'Karachi';
  print(a.name);
  print(b.name);
}
output
Lahore
Karachi

Question 4 — Solution

Student names the class — the blueprint. Student() creates a new object from it.

Question 5 — Solution

dart
class Circle {
  double radius = 0;

  double area() {
    return 3.14 * radius * radius;
  }
}

void main() {
  var circle = Circle();
  circle.radius = 10;
  print(circle.area());
}
output
314.0

Question 6 — Solution

dart
class Lamp {
  bool isOn = false;

  void toggle() {
    isOn = !isOn;
  }
}

void main() {
  var lamp = Lamp();
  lamp.toggle();
  lamp.toggle();
  lamp.toggle();
  print(lamp.isOn);
}
output
true

Question 7 — Solution

dart
class Product {
  String name = '';
  int price = 0;

  int priceFor(int quantity) {
    return price * quantity;
  }
}

void main() {
  var tea = Product();
  tea.name = 'tea';
  tea.price = 120;
  print(tea.priceFor(3));
}
output
360

Question 8 — Solution

Encapsulation (Lecture 057), inheritance (Lecture 059), polymorphism (Lecture 065) and abstraction (Lectures 062 and 063).

Question 9 — Solution

dart
class Wallet {
  int balance = 0;

  bool pay(int amount) {
    if (amount > balance) {
      return false;
    }
    balance -= amount;
    return true;
  }
}

void main() {
  var wallet = Wallet();
  wallet.balance = 500;
  print(wallet.pay(200));
  print(wallet.pay(400));
  print(wallet.balance);
}
output
true
false
300

Question 10 — Solution

dart
class Student {
  String name = '';
  List<int> marks = [];

  int highest() {
    var best = marks[0];
    for (final mark in marks) {
      if (mark > best) {
        best = mark;
      }
    }
    return best;
  }
}

void main() {
  var sara = Student();
  sara.name = 'Sara';
  sara.marks = [72, 95, 88];
  print('${sara.name}: ${sara.highest()}');
}
output
Sara: 95

Quick Revision

  1. What two things does every object have?
  2. What is the difference between a class and an object?
  3. What is a field? What is a method?
  4. What does Student() do?
  5. If two objects come from the same class, does changing one change the other?
  6. Why is ali.nmae better than ali['nmae']?
  7. Name the four pillars of OOP.

Key Takeaways

  • An object bundles state (data) with behaviour (actions).
  • A class is the blueprint; each object made from it is an instance.
  • Strings and lists are objects too — String and List are classes.
  • Fields are variables in a class; methods are functions in a class.
  • ClassName() creates a new object; the dot reads fields and calls methods.
  • Every object has its own copy of the fields, and a method works on the object it is called on.
  • A class gives each field its own type and turns typos into compile-time errors.
  • The four pillars — encapsulation, inheritance, polymorphism, abstraction — each get their own lectures.

What's Next?

Lecture 53 — Creating Classes & Objects. You have seen the idea and a first class. Next we look closely at how classes and objects work in Dart: fields, methods, creating instances, setting fields with the cascade operator, and what really happens when two variables refer to the same object.


Video lecture

Subscribe
Placeholder video — the real recording isn't linked yet.