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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
List all Dart tutorials.