Lets study about one of the most important part of a modern day language, without which these days a programming language is not complete, classes! Classes in Dart are simple yet they bring many new tricks to that table.
Classes in Dart
Here is how you declare a simple class in Dart and create an instance of it.
1 2 3 4 5 6 7 |
main(List<String> args) { Dog d = new Dog(); } class Dog { } |
Now we will add instance variable in the class along with a constructor, lets add a name field and a age field for the Dog class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
main(List<String> args) { Dog d = new Dog('Duffy', 2); print(d.name); } class Dog { String name; int age; Dog(String name, String age) { this.name = name; this.age = age; } } |
Dart provides a syntactic way to define the plain old constructor. Here is how.
1 2 3 4 5 6 7 8 9 10 11 |
main(List<String> args) { Dog d = new Dog('Duffy', 2); print(d.name); } class Dog { String name; int age; Dog(this.name, this.age); } |
As you can see we have written a one line constructor, the first parameter value will be set to name and the second parameter value will be set to age.
Named Constructors
Dart provides another way to define a constructor, called named constructor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
main(List<String> args) { Dog d = new Dog.newBorn(); print(d.name); } class Dog { String name; int age; Dog(this.name, this.age); Dog.newBorn() { name = 'Doggy'; age = 0; } } |
As you can see we have provided a name for the constructor. All it does is add more clarity when using different constructor.
Inheritance
You can inherit other classes in Dart using the extend keyword.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
main(List<String> args) { Pug p = new Pug('Duffy', 5); print(p.name); } class Dog { String name; int age; Dog(this.name, this.age); Dog.newBorn() { name = 'Doggy'; age = 0; } } class Pug extends Dog { Pug(String name, int age): super(name, age); } |
Here our Pug class inherits from the Dog class and calls the constructor of the Dog class with appropriate parameters using the super keyword.
You can also call other constructor within in the same class by using the keyword this after the colons( : ).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
main(List<String> args) { Pug p = new Pug.small('Duffy'); print(p.name); } class Dog { String name; int age; Dog(this.name, this.age); Dog.newBorn() { name = 'Doggy'; age = 0; } } class Pug extends Dog { Pug(String name, int age): super(name, age); Pug.small(String name): this(name, 1); Pug.large(String name): this(name, 3); } |
Here we create two named constructors that take in only the name of dog and call the default Pug constructor.
Methods
Method in a class are just similar to defining methods independently in Dart.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
main(List<String> args) { Dog d = new Dog('Duffy', 10); d.bark(); } class Dog { String name; int age; Dog(this.name, this.age); Dog.newBorn() { name = 'Doggy'; age = 0; } bark() { print('Bow Wow'); } } |
Overriding methods is just as simple as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
main(List<String> args) { Pug p = new Pug.small('Duffy'); p.bark(); } class Dog { String name; int age; Dog(this.name, this.age); Dog.newBorn() { name = 'Doggy'; age = 0; } bark() { print('Bow Wow'); } } class Pug extends Dog { Pug(String name, int age): super(name, age); Pug.small(String name): this(name, 1); Pug.large(String name): this(name, 3); @override bark() { print('Meow!'); } } |
Getter and Setters
By default any variable you define in a class is accessible by the just referring to the name of variable on the object, e.g. dog.name, value in name can be assessed and assigned directly. But sometimes you want custom getter and setter for a property, in Dart you can use get and set keywords do define custom getter and setter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
main(List<String> args) { Dog d = new Dog('Duffy', 5); d.respectedName = 'Mr.Duffy'; print(d.respectedName); } class Dog { String name; int age; Dog(this.name, this.age); String get respectedName { return 'Mr.$name'; } set respectedName(String newName) { name = newName; } Dog.newBorn() { name = 'Doggy'; age = 0; } bark() { print('Bow Wow'); } } |
Now you might think that the name is still visible and can be changed at will, let’s fix that my making name property private.
Controlling Accessibility
By default every property and method you define in a class is public and can be accessed directly. In Dart you have the ability to make any variable or method private by just appending ‘_’ in front of its name. Let’s make the name property private.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
main(List<String> args) { Dog d = new Dog('Duffy', 5); print(d.name); //This will throw error } class Dog { String _name; int age; Dog(this.name, this.age); String get respectedName { return 'Mr.$name'; } set respectedName(String newName) { name = newName; } Dog.newBorn() { name = 'Doggy'; age = 0; } bark() { print('Bow Wow'); } _hiddenMethod() { print('I can only be called internally!'); } } |
Abstract Classes and Methods
You can make an abstract class in Dart using the abstract keyword.
1 2 3 4 5 |
abstract class AbstractDog { void bark(); void _hiddenMethod(); } |
You only need to provide the keyword before the class declaration, and don’t need it for methods. For methods just provide the signature and leave out the implementation.
Static Methods
To make a field/method static just prefix the keyword static before its declaration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
main(List<String> args) { Dog.bark(); } class Dog { String name; int age; Dog(this.name, this.age); static bark() { print('Bow Wow'); } } |
Enum
Dart has support for enums and use like everything else, you will be familiar with them if you come from a language say Java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
main(List<String> args) { Dog d = new Dog('Duffy', 12, CurrentState.sleeping); print(d.state == CurrentState.sleeping); //Prints 'true' } enum CurrentState { sleeping, barking, eating, walking } class Dog { String name; int age; CurrentState state; Dog(this.name, this.age, this.state); static bark() { print('Bow Wow'); } } |
Generics
Dart has full support for generics. Lets say you are writing a class that just holds data in it and you want to make it such that it can hold any kind of data. Here is how you will write that class using generics.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
main(List<String> args) { DataHolder<String> dataHolder = new DataHolder('Some data'); print(dataHolder.getData()); dataHolder.setData('New Data'); print(dataHolder.getData()); } class DataHolder<T> { T data; DataHolder(this.data); getData() { return data; } setData(data) { this.data = data; } } |
Next Tutorial >> Just enough Dart for Flutter – Tutorial 04 – Asynchronous and Libraries.
Previous Tutorial << Just enough Dart for Flutter – Tutorial 02 – Control Flow and Exceptions.
9 Comments
Palaniraja · July 10, 2018 at 4:16 pm
Thanks for the dart posts. There were lot of typos for String as “Stirng”
Gurleen Sethi · March 11, 2019 at 3:22 am
Thank you for pointing out. I have fixed them.
Surya · January 8, 2019 at 7:45 am
I really enjoyed your crash course on flutter. This really helped me get started right away with flutter. Please do more of these flutter series!. Also more on dart topics please! thank you so very much!
Ayman Ahmed · January 8, 2019 at 8:16 pm
Thank you for this great post. Could you please add information related to class constructor, and the colon(:) operator after the contractor. It is confusing, I just understood it after reading below thread:
https://stackoverflow.com/a/50274735/1680637
Maruf Alom · June 21, 2019 at 3:43 pm
Nicely written. Would you be kind to write another article about Generics?
Koustubh Kulkarni · January 8, 2020 at 6:44 am
Nice explanation in simple and easy to understand examples !
Thanks !
Tech · January 21, 2020 at 3:17 pm
class Pug extends Dog {
Pug(String name, int age): super(name, age);
Pug.small(String name): this(name, 1);
Pug.large(String name): this(name, 3);
}
Thanks for the tutorial.And please can you explain more about Pug.small and :
Just enough Dart for Flutter – Tutorial 02 – Control Flow and Exceptions - TheTechnoCafe · June 12, 2018 at 7:03 pm
[…] Next Tutorial >> Just enough Dart for Flutter – Tutorial 03 – Classes and Generics… […]
Just enough Dart for Flutter - Tutorial 04 - Asynchronous and Libraries - TheTechnoCafe · June 12, 2018 at 7:05 pm
[…] Previous Tutorial << Just enough Dart for Flutter – Tutorial 03 – Classes and Gene… […]