Introduction
In this article, I would be discussing Object oriented Programming feature supported by DART language, though it’s not elaborate as current or older market shaker languages like C++, C#. However, it has given enough toolsets/concept to provide programmer comfort while programming.
Background
Almost every programmer agrees with the fact that OOPs is made of these four principals, I will explore this with respect to DART language:
Abstraction
: DART supports only two types of data access, public
and private
, no good old protected
here and to define any function or variable private
, use _
(underscore
) Encapsulation
: In this principal, DART is similar to rest of the language, it also provides shell (class
) to capsule data and business logic. Polymorphism
: Polymorphism is divided into two concepts:
Compiletime polymorphism
: DART doesn't support function overloading, though it supports operator overloading Runtime polymorphism
: DART supports function overriding using @override
keyword
Inheritance
- DART supports only single or multi-level inheritance using extends
keyword. Though it doesn't support multiple inheritance, you can implement multiple class into one using implements
keyword
I would discuss each point with some coding, let our journey begin.
Using the Code
Task#1: Abstraction and Encapsulation
As mentioned earlier, Abstraction has two types of data access, which are private
and public
. By default, every function and variable is public
in DART Class, in comparison to other popular OOPs language like C# and C++, every item is private
by default. Reason I believe might be it's closer to javascript.
Secondly, there is no protected
keyword in DART, here is small program demonstrating Encapsulation and Abstraction, here I am making class variable as private
, please see to make variable private
I have used _
(underscore) to make variable private
. For Encapsulation, we are creating class, which provides capsule or shell to hold variable and methods together and limit the scope of variable till the lifetime of class object.
class AbstractionEncapsulation {
String title;
AbstractionEncapsulation(String argtitle) : title = argtitle {
print("in default constructor $title");
}
AbstractionEncapsulation.fromAnotherObject(
AbstractionEncapsulation abstEncap) {
this.title = abstEncap.title;
}
printTitle() {
print(title);
}
}
void testabstractionencapsulation() {
print("testabstractionencapsulation start");
AbstractionEncapsulation abstractionEncapsulation =
new AbstractionEncapsulation('hello');
AbstractionEncapsulation abstractionEncapsulation1 =
new AbstractionEncapsulation.fromAnotherObject(abstractionEncapsulation);
abstractionEncapsulation1.printTitle();
}
Constructor/Destructor
There is no concept of destructor in DART, as it is a garbage collected language, whenever class object holds no reference, it would be removed from memory. Since there is no concept weak references (till the time of writing this article) or pointer in DART. This DART runtime manages removal of object memory, when it's not referenced by any other object.
You can have only one default/parameterised constructor in DART class, rest should be named one as DART doesn't support method overloading, so name of function should be different, otherwise you would get compile time error, reason for majority of time DART programs are fashioned to alternate to JavaScript, so it took lot of concepts from there. Since it's still maturing, hopefully it supports function overloading in future.
Task#2: Inheritance
Let me explain Inheritance in DART first before describing polymorphism. As for overriding or runtime polymorphism, we require Inheritance. Now as mentioned earlier, DART supports single and Multi-Level inheritance using extends
, Though Multiple Inheritance is not supported, you can implement multiple class into new class using implements
keyword. Main difference between extending and implementing is that when you extend, you will extending the class functionality (the main feature of Inheritance) however when you are implementing, you are composing class from one or more class. From DART website:
Quote:
Every class implicitly defines an interface containing all the instance members of the class and of any interfaces it implements. If you want to create a class A that supports class B’s API without inheriting B’s implementation, class A should implement the B interface.
Let's check how to do single inheritance in DART:
abstract class Shape {
String get name;
set length(int ilen);
set breath(int ibre);
num getArea();
}
class Rectangle extends Shape {
int _length, _breath;
@override
set breath(int ibre) {
_breath = ibre;
}
@override
num getArea() {
return _length * _breath;
}
@override
set length(int ilen) {
_length = ilen;
}
@override
String get name => 'Rectangles';
}
testsingleinheritencedart() {
singleinheritencedart.Shape sh = new singleinheritencedart.Rectangle();
sh.breath = 10;
sh.length = 10;
print("the area of ${sh.name} is ${sh.getArea()}");
}
This code will showcase multiple inheritance in DART, here I am creating class circle
by implementing both Shape
class from the previous example and ShapePerimeter
:
import 'package:dart4_oops/singleinheritence.dart';
abstract class ShapePerimeter {
num getPerimeter();
}
class Circle implements ShapePerimeter, Shape {
int _length;
@override
set breath(int ibre) {
}
@override
num getArea() {
return (3.14 * _length * _length);
}
@override
num getPerimeter() {
return (2 * 3.14 * _length);
}
@override
set length(int ilen) {
_length = ilen;
}
@override
String get name => 'Circle';
}
testmultipleinheritencedart() {
singleinheritencedart.Shape sh = new multipleinheritencedart.Circle();
sh.length = 10;
multipleinheritencedart.ShapePerimeter sp =
sh as multipleinheritencedart.Circle;
print("the area of ${sh.name} is ${sh.getArea()}");
print("the perimeter of ${sh.name} is ${sp.getPerimeter()}");
}
Task#3: Polymorphism
Now till this point, you are aware how Abstraction, Encapsulation and Inheritance have been implemented in DART, now let's learn the last principle of OOPs now. Polymorphism whose literal meaning is to be existing in multiple forms. DART polymorphism is not as extensive, however there is lot of workaround to achieve similar results. First of all, method overloading is not supported, i.e.:
Following code wouldn't be compiled in DART, which is a very common scenario in C++/ C# to demonstrate method overloading:
void Overloading1(int a){}
void Overloading1(int a,int b){}
However, similar functionality could be achieved using named
and optional
parameters (though it makes function bloat and with against SOLID principle). C# supports both named and optional parameters, and C++ support only later. For optional parameter, we use []
(Square bracket) and named parameter is specified in {}
(curly bracket).
Using optional parameter - Using named parameter
class Overloading {
final int Price;
Overloading({this.Price});
int getTyrePrice(int iTyres, [int price]) {
if (price != null) return iTyres * price;
return iTyres * Price;
}
String getTyreBrand(int price, {int multiple}) {
int iprice = price;
if (multiple != null) iprice *= multiple;
if (iprice < 100)
return "APOLLO TYRES";
else if (iprice < 200)
return "BRIDGESTONE ";
else if (iprice < 500) return "MICHELIN ";
return "Tyre not available";
}
}
testOverloadingdart() {
Overloading obj = new Overloading(Price: 100);
print(obj.getTyrePrice(5));
print(obj.getTyrePrice(5, 200));
print(obj.getTyreBrand(150));
print(obj.getTyreBrand(90, multiple: 3));
}
However, don't get disheartened if there is no support for Function overloading, however DART supports operator overloading. Here is a list of overridable operator from DART website.
Overridable operators
< | + | | | [] |
> | / | ^ | []= |
<= | ~/ | & | ~ |
>= | * | << | == |
– | % | >> | |
Let's do some coding to demonstrate the same, here I am overloading +
operator.
class OperatorOverload {
int value = 0;
operator +(int i) {
this.value += i;
}
}
void testOperatorOverload() {
OperatorOverload oo = new OperatorOverload();
print("initial value ${oo.value}");
oo.value += 10;
print("new value ${oo.value}");
}
With this, compile time polymorphism is complete, let's dive into runtime polymorphism using inheritance and overriding.
Bonus: Factory Constructor
This is a unique type of constructor introduced in DART. Firstly, factory
keyword would be applied only on constructor. You can use this to create Singleton and Factory pattern based class. Here, let's dive straight into the code to understand it properly.
Factory Constructor based Singleton pattern: Though it's not fulfilling number 1 condition of Singleton pattern, which is making constructor private
, however I am fullfilling the second condition of control over object creation.
class Singleton {
static Singleton _objSingleton;
String _information;
String get Information => _information;
set Information(String info) {
_information = info;
}
Singleton() {}
factory Singleton.Me() {
if (_objSingleton == null) _objSingleton = new Singleton();
return _objSingleton;
}
}
void testSingleton() {
Singleton singleton = new Singleton.Me();
singleton.Information = "Information from first Object";
print("From singleton object :" + singleton.Information);
Singleton singleton1 = new Singleton.Me();
print("From singleton1 object :" + singleton1.Information);
}
Note: Dart currently supports single thread only, so there is no concept of locking or Mutex in DART, which is very common sighting in C#/C++ code when you are creating singleton object dynamically, where thread synchronization code is added just to ensure that object is created only once.
Factory Constructor based Factory Pattern: I utilize abstract
class and using factory constructor, I am making sure the type of object I need:
enum EAnimal { Lion, Cat }
abstract class Animal {
Animal() {}
factory Animal.GetAnimal(EAnimal animal) {
switch (animal) {
case EAnimal.Lion:
return new Loin();
case EAnimal.Cat:
return new Cat();
default:
return null;
}
}
String SayHello();
}
class Cat extends Animal {
@override
String SayHello() {
return "Cat say meow";
}
}
class Loin extends Animal {
@override
String SayHello() {
return "Loin Roar";
}
}
void testFactoryPattern() {
print(new Animal.GetAnimal(EAnimal.Lion).SayHello());
print(new Animal.GetAnimal(EAnimal.Cat).SayHello());
}
With this, I have reached the end of this tutorial. Thanks for reading, please do share your comments. You can reach me by twitter too, my handle is @thatsalok.
Points of Interest
Flutter Tutorial
- Flutter Getting Started: Tutorial #1
- Flutter Getting Started: Tutorial 2 - StateFulWidget
- Flutter Getting Started: Tutorial 3 Navigation
- Flutter Getting Started: Tutorial 4 ListView
- Flutter Getting Started: Tutorial 5 Grid
DART Series
- DART2 Prima Plus - Tutorial 1
- DART2 Prima Plus - Tutorial 2 - LIST
- DART2 Prima Plus - Tutorial 3 - MAP
History
- 31-July-2018 - First version