ZetCode

Dart object

last modified January 28, 2024

Dart object tutorial shows how to work with objects in Dart language. An object is a basic building block of a Dart program.

Object

Objects are basic building blocks of a Dart program. An object is a combination of data and methods. The data and the methods are called members of an object. Objects communicate together through methods. Each object can receive messages, send messages and process data.

There are two steps in creating an object. First, we define a class. A class is a template for an object. It is a blueprint which describes the state and behavior that the objects of the class all share. A class can be used to create many objects. Objects created at runtime from a class are called instances of that particular class. A new instance is created with the new keyword; since Dart 2.0, the keyword is optional.

Objects have members consisting of functions and data. We use a dot (.) operator to refer to an instance variables or methods.

Object-oriented programming (OOP) is a programming paradigm that uses objects and their interactions to design applications and computer programs.

Dart objects

In Dart, we work with objects. Even numbers or string literals are objects.

main.dart
class Being {}

void main() {
  var b = Being();

  print(b.hashCode);
  print("falcon".toUpperCase());
  print(2.isNegative);

  print(b.runtimeType);
  print(2.runtimeType);
}

In the example, we work with various objects.

class Being {}

With the class keyword, we define a template for an object. In our case, the definition is empty.

var b = Being();

We create a new instance of a Being. The new keyword is optional.

print(b.hashCode);

Even though the object is empty, it has some built-in methods and attributes. This is because all created objects implicitly inherit from the mother of all objects: the Object.

print("falcon".toUpperCase());

The "falcon" is a string literal, which is an object itself. (This is not true for many other computer languages.) We call the object's toUpperCase method.

print(2.isNegative);

Even number literals are objects.

print(b.runtimeType);
print(2.runtimeType);

Here we check the runtime types of two objects.

$  dart objects.dart
511903303
FALCON
false
Being
int

Dart object attributes

Object attributes is the data bundled in an instance of a class. The object attributes are called instance variables or member fields. An instance variable is a variable defined in a class, for which each object in the class has a separate copy.

All instance variables generate an implicit getter method. Non-final instance variables also generate an implicit setter method.

main.dart
class Person {
  var name;
  var occupation;
}

void main() {
  var p1 = Person();
  p1.name = "John Doe";
  p1.occupation = "gardener";

  var p2 = Person();
  p2.name = "Roger Roe";
  p2.occupation = "driver";

  print("${p1.name} is a ${p1.occupation}");
  print("${p2.name} is a ${p2.occupation}");
}

We have a class with two member fields: name and occupation.

var p1 = Person();
p1.name = "John Doe";
p1.occupation = "gardener";

We create a new Person object and set the two attributes.

var p2 = Person();
p2.name = "Roger Roe";
p2.occupation = "driver";

A completely new object with its unique attributes is created.

print("${p1.name} is a ${p1.occupation}");
print("${p2.name} is a ${p2.occupation}");

We output the attributes of the two objects.

$ dart main.dart
John Doe is a gardener
Roger Roe is a driver

Dart cascade operator

The cascade operator (..) allows us to perform a sequence of operations on the same object.

main.dart
class User {
  var fname;
  var lname;
  var occupation;
  String toString() {
    return "$fname $lname is a $occupation";
  }
}

void main() {
  var u = User();
  u
    ..fname = "Roger"
    ..lname = "Roe"
    ..occupation = "driver";

  print(u);
}

The program initializes a User object using the cascase operator.

$ dart main.dart 
Roger Roe is a driver

Dart object methods

Methods are functions defined inside the body of a class. They are used to perform operations with the attributes of our objects. Methods bring modularity to our programs.

main.dart
import 'dart:math';

class Circle {
  int radius;

  double area() {
    return this.radius * this.radius * pi;
  }
}

void main() {
  var c = Circle();
  c.radius = 5;

  print(c.area());
}

In the code example, we have a Circle class. Its area method computes the area of a circle.

double area() {
  return this.radius * this.radius * pi;
}

The area method returns the area of a circle. The pi is a constant form the dart:math library.

var c = Circle();
c.radius = 5;

A new circle is created. We set its radius attribute.

print(c.area());

We call the area method of the circle object through the dot operator.

$ dart main.dart
78.53981633974483

Dart object constructor

A constructor is a special kind of a method. It is automatically called when the object is created. Constructors do not return values. The purpose of the constructor is to initiate the state of an object.

There are two basic types of constructors in Dart: named constructors and factory constructors.

Named constructors have the same name as the class. The following example uses a named constructor.

main.dart
class User {
  String name;
  String occupation;

  User(String name, String occupation) {
    this.name = name;
    this.occupation = occupation;
  }
}

void main() {
  var u1 = new User("John Doe", "gardener");
  var u2 = new User("Roder Roe", "driver");

  print("${u1.name} is a ${u1.occupation}");
  print("${u2.name} is a ${u2.occupation}");
}

We have a User class. Its constructor initiates two attributes: name and occupation.

User(String name, String occupation) {
  this.name = name;
  this.occupation = occupation;
}

If the names of the object attributes and constructor arguments are the same, we refer to the object attributes with the this keyword.

var u1 = new User("John Doe", "gardener");

When we create a new User object, we pass the constructor two values.

$ dart main.dart
John Doe is a gardener
Roder Roe is a driver

In the next example, we have a factory constructor. They are created with the factory keyword. Factory constructors do use the return keyword. You cannot refer to this within the factory constructor.

Factory constructors are used when implementing caching, initializing a final variable using logic that can't be handled in the initializer list, or hiding the implementation details of the object construction. Factory is also one of the basic desing patterns for developing large projects.

main.dart
import 'dart:math';

abstract class Shape {
  factory Shape(String type) {
    if (type == 'circle') {
      return Circle(4);
    } else if (type == 'square') {
      return Square(4);
    } else if (type == 'triangle') {
      return Triangle(4);
    } else {
      throw new Exception("Unknown shape");
    }
  }
  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => pi * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

class Triangle implements Shape {
  final num side;
  Triangle(this.side);
  num get area => pow(side, 2) / 2;
}

void main() {
  print(Shape('circle').area);
  print(Shape('square').area);
  print(Shape('triangle').area);
}

We have an abstract Shape class with a factory constructor. The constructor creates a Circle, Square, and Triangle shapes.

$ dart main.dart 
50.26548245743669
16
8.0

Dart toString method

Each object has a toString method inherited from the Object superclass. It returns a human-readable representation of an object. Note that when we call the print method with an object as a parameter, the toString is being called.

main.dart
class User {
  String name;
  String occupation;

  User(this.name, this.occupation);

  String toString() {
    return "$name is a $occupation";
  }
}

void main() {
  var u1 = new User("John Doe", "gardener");
  var u2 = new User("Roder Roe", "driver");

  print(u1);
  print(u2);
}

We have the User class in which we override the default implementation of the toString method.

String toString() {
  return "$name is a $occupation";
}

The toString method tells the name of the user and his occupation.

print(u1);
print(u2);

The toString is called for both objects; we do not need to call the method explicitly.

Dart automatic initializers

Dart has syntax for automatic initialization of attributes in the constructor.

main.dart
class User {
  String name;
  String occupation;

  User(this.name, this.occupation);
}

void main() {
  var u1 = new User("John Doe", "gardener");
  var u2 = new User("Roder Roe", "driver");

  print("${u1.name} is a ${u1.occupation}");
  print("${u2.name} is a ${u2.occupation}");
}

We pass this.name and this.occupation to the constructor. We don't need to specify the data types; they are inferred.

Dart named parameters

With {}, we can create named parameters. When passing a value to the constructor, we need to prefix it with the name of the parameter.

main.dart
class User {
  String name;
  String occupation;

  User({this.name, this.occupation});

  String toString() {
    return "$name is a $occupation";
  }
}

void main() {
  var u1 = new User(name: "John Doe", occupation: "gardener");
  print(u1);
}

We have an example with named parameters.

Dart object inheritance

The inheritance is a way to form new classes using classes that have already been defined. The newly formed classes are called derived classes, the classes that we derive from are called base classes. The derived classes (descendants) override or extend the functionality of the base classes (ancestors).

We use the extends keyword to inherit from a parent class.

main.dart
class Being {
  static int count = 0;

  Being() {
    count++;
    print("Being is created");
  }

  void getCount() {
    print("There are $count Beings\n");
  }
}

class Human extends Being {
  Human() {
    print("Human is created");
  }
}

class Animal extends Being {
  Animal() {
    print("Animal is created");
  }
}

class Dog extends Animal {
  Dog() {
    print("Dog is created");
  }
}

void main() {
  Human();
  var dog = Dog();
  dog.getCount();
}

The Human and the Animal classes inherit from the Being class. The Dog class inherits directly from the Animal class and indirectly from the Being class. We also introduce a concept of a static variable.

static int count = 0;

We define a static variable. Static members are members that are shared by all instances of a class.

Being() {
  count++;
  print("Being is created");
}

Each time the Being class is instantiated, we increase the count variable by one. This way we keep track of the number of instances created.

class Animal extends Being {
...
class Dog extends Animal {
...

The Animal inherits from the Being and the Dog inherits from the Animal. Indirectly, the Dog inherits from the Being as well.

Human();
var dog = Dog();
dog.getCount();

We create instances from the Human and from the Dog classes. We call the getCount method of the Dog object.

$ dart main.dart
Being is created
Human is created
Being is created
Animal is created
Dog is created
There are 2 Beings

Dart check type

In Dart, we can check the type with the is keyword.

main.dart
class Person {}

class Student {}

void main() {
  var p = Person();
  var s = Student();

  print(p is Person);
  print(s is Person);
  print(p is Object);
  print(s is Object);

  print(2 is int);
  print(2 is Object);
}

In the example, we check the types of several objects.

print(p is Person);

We check if p is of type Person, which is true.

print(s is Person);

We check if s is of type Person, which is not true.

print(2 is Object);

Since all objects implicitly inherit from Object, this line prints true.

$ dart main.dart
true
false
true
true
true
true

Source

Dart classes - language reference

In this article we have covered objects in Dart.

Author

My name is Jan Bodnar and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all Dart tutorials.