Skip to content
English
On this page

Dart

Numbers

Documentation

The syntax for declaring a number is as given below

int var_name;      // declares an integer variable 
double var_name;   // declares a double variable
void main() {
   // declare an integer
   int num1 = 10;             
     
   // declare a double value
   double num2 = 10.50;  

   // print the values
   print(num1);
   print(num2);
}

Number Properties

The following table lists the properties supported by Dart numbers.

Property & Description
1hashcode: Returns a hash code for a numerical value.
2isFinite: True if the number is finite; otherwise, false.
3isInfinite: True if the number is positive infinity or negative infinity; otherwise, false.
4isNan: True if the number is the double Not-a-Number value; otherwise, false.
5isNegative: True if the number is negative; otherwise, false.
6sign: Returns minus one, zero or plus one depending on the sign and numerical value of the number.
7isEven: Returns true if the number is an even number.
8isOdd: Returns true if the number is an odd number.

Number Methods

Given below are a list of commonly used methods supported by numbers −

1abs: Returns the absolute value of the number.
2ceil: Returns the least integer no smaller than the number.
3compareTo: Compares this to other number.
4Floor: Returns the greatest integer not greater than the current number.
5remainder: Returns the truncated remainder after dividing the two numbers.
6Round: Returns the integer closest to the current numbers.
7toDouble: Returns the double equivalent of the number.
8toInt: Returns the integer equivalent of the number.
9toString: Returns the string equivalent representation of the number.
10truncate: Returns an integer after discarding any fractional digits.

String interpolation

ts
int x=6;
   int y=2;
   String sum = '${x+y}';          // result is 8
   String subtraction = '${x-y}';  // result is 4
   String upperCase = '${"hello".toUpperCase()}'; // result is HELLO
   String concatXY = '$x$y'; // result is '62'

Functions

Dart lang is an OOL(Object-oriented language), In this language, functions are objects and have a type, Function. This implies that functions can be assigned to variables or passed as args to other functions. Interestingly, you can also call an instance of a class as if it were a fuction. That's awesome, right?

ts
String fullName(){
       String firstName = "Temidayo";
       String lastName = "Adefioye";
       return '$firstName $lastName'; // returns 'Temidayo Adefioye'
   }
ts
int length(String text){
       return text.length; // returns length of text
   }

The above function can be rewritten in a more concise way:

ts
int length(String text) => return text.length; // returns length of text

The above approach is applicable where functions contain just ONE expression. This is also referred to as shorthand syntax.

Optional Parameters

To specify optional positional parameters, use square [] brackets.

void function_name(param1, [optional_param_1, optional_param_2]) { }

If an optional parameter is not passed a value, it is set to NULL.

ts
void main() { 
   test_param(123); 
}  
test_param(n1,[s1]) { 
   print(n1); 
   print(s1); 
}

Optional Named Parameter

Unlike positional parameters, the parameters’ name must be specified while the value is being passed. Curly brace {} can be used to specify optional named parameters.

Syntax - Declaring the function

void function_name(a, {optional_param1, optional_param2}) { }

Syntax - Calling the function

function_name(optional_param:value,…);

ts
void main() { 
   test_param(123); 
   test_param(123,s1:'hello'); 
   test_param(123,s2:'hello',s1:'world'); 
}  
test_param(n1,{s1,s2}) { 
   print(n1); 
   print(s1); 
}

Optional Parameters with Default Values

Function parameters can also be assigned values by default. However, such parameters can also be explicitly passed values.

ts
void main() { 
   test_param(123); 
}  
void test_param(n1,{s1:12}) { 
   print(n1); 
   print(s1); 
}

Recursive Dart Functions

Recursion is a technique for iterating over an operation by having a function call to itself repeatedly until it arrives at a result. Recursion is best applied when you need to call the same function repeatedly with different parameters from within a loop.

ts
void main() { 
   print(factorial(6));
}  
factorial(number) { 
   if (number <= 0) {         
      // termination case 
      return 1; 
   } else { 
      return (number * factorial(number - 1));    
      // function invokes itself 
   } 
}

Lambda Functions

Lambda functions provide you with a short and concise way of representing small functions. They are also referred to as Arrow functions. In dart, if you need to write quick throw away functions without necessarily naming them, lambda fucntion is all you need. With the power of this function you can do the following and more:

ts
var numList = new List<int>.generate(5,(i) => i);
   print(numList); //result: {0,1,2,3,4}
   var loans = numList.map( (n) => "\#$n").toList();
   print(loans); // result: {#0, #1, #3, #4}

   printMsg()=> print("Hello world");

   // You can declare a state function this way in flutter
    _DashboardState createState() => _DashboardState(); 

   // How about creating a widget using lambda?
   Card makeCard(Asset assetViewModel) => Card(
         elevation: 8.0,
         margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
         child: Container(
           decoration: BoxDecoration(color: Colors.white),
           child: makeListTile(assetViewModel), // where makeListTile is a custom widget created already
         ),
   );

Parsing

Parsing a string to a number such as integer and double is very key. As a developer, often times I need to convert(parse) a string value coming from a server-side to a number, tryParse method comes in handy. Take a look at this code snippet:

ts
var a = "121";
var b = "120.56";
var c = "100.a12";         
var d = "abc";
String parseA = int.tryParse(a); // result is 121
String parseB = double.tryParse(b); // result is 120.56
String parseC = double.tryParse(c); // result is null (that string contains invalid number)
String parseD = double.tryParse(d); // result is null (that string contains invalid number)

List Arrays

Perhaps the most common collection in nearly every programming language is the array or ordered set of objects. Please note that Dart arrays are Lists.

ts
var numList = [1,2,3,5,6,7];
var countryList = ["Nigeria","United States","United Kingdom","Ghana","IreLand","Germany"];
String numLength = numList.length; // result is 6
String countryLength = countryList.length; // result is 6
String countryIndex = countryList[1]; // result is 'United States'
String numIndex = numList[0]; // result is 1

countryList.add("Poland"); // Adds a new item to the list.

var emailList = new List(3); // Set a fixed list size 
var emailList = new List<String>(); // instance of a list of type String

Null-aware Operators

Handling null exceptions in app development is very essential, as this allows you to create a seamless experience for your app users. Dart provides you with some handy operators for dealing with values that might be null. One is the ??= assignment operator, which assigns a value of a variable only if that variable is currently null:

ts
int x; // The initial value of any object is null
x ??=6;
print(x); // result: 6

x ??=3;
print(x); // result is still 6

print(null ?? 10); // result: 10. Display the value on the left if it's not null else return the value on the right

Conditional Property Access

To properly safegaurd access to a property or method of an object that might be null, put a question mark (?) before the (.)

ts
userObject?.userName

//The code snippet above is equivalent to following:

(userObject !=null) ? userObject.userName : null

//You can chain multiple uses of ?. together in a single expression

userObject?.userName?.toString()

// The preceeding code returns null and never calls toString() if either userObject or userObject.userName is null

Collections Literals

With literals you can create Dart's built-in lists, maps and sets without hassle.

ts
final fruitList = ["Orange","Bannana","Carrot","Apple"]; // A list of fruit
final countrySet = {"Nigeria","United States","Poland","Italy"}; // A set of country
final credMap = {
   'userName': 'temi',
   'password': 'xmen'
} // A map of user credentials

You maybe wondering why we didn't explicitly declare a type for all of the collections above. It's interesting to know that dart's type inference can assign types to these variables for you. In this case, the inferred types are List, Set and Map<String,String>.

Please note that you can choose to specify a type for your variable declaration like this:

ts
final fruitList = <String>[];
final countrySet = <String>{};
final credMap = <String, String>{};

Arrow Syntax

Remember Lambda Functions as discussed earlier in this sheet? We used a symbol => to define our lambda expression. You can check out Lambda function section for more explanation.

ts
String _firstName = "Michael";
String _lastName = "Jones";
String _middleName = "Will";

String get fullName => '$_firstName $_middleName $_lastName'; // result: 'Michael Will Jones'

Iterations

Just like every other programming language out there, you can perform iterations in dart. Here is a for loop example

ts
for (int i=0; i<=20; i++){
   print(i); // prints 1 to 20
}

var fruitList = ["Orange","Bannana","Carrot","Apple"];
for (final fruit in fruits){
   print(fruit); // prints all types of fruit in the list
}

Map

Map can either be declared using literals or map constructor. To learn more about map declaration using literals, please go to the Collections Literals section. Here is how you can declare map using a map constructor:

ts
var user = new Map();
// To initialize the map, do this:
user['firstName'] = 'Paul';
user['lastName'] = 'Pogba';

// Result: {firstName: Paul, lastName: Pogba}


// Below are map properties

- Keys
- Values
- Length
- isEmpty
- isNotEmpty

// Below are map functions

- addAll()
- clear()
- remove()
- forEach()

Variables

ts
int x = 2; // explicitly typed
var p = 5; // type inferred
p = "cool"; // ops! throws an error
dynamic z = 8; // variable can take on any type
z = "cool"; // cool

// if you never intend to change a variable use final or const. Something like this:

final email = "temid@gmail.com"; // you can't change the value
final String email = "temid@gmail.com"; // you can't change the value

// iPhone 11 Pro max calculator using const

const qty = 5;
const totalCost = 1099 * qty;

Loops

At times, certain instructions require repeated execution. Loops are an ideal way to do the same. A loop represents a set of instructions that must be repeated. In a loop’s context, a repetition is termed as an iteration.

Let’s start the discussion with Definite Loops. A loop whose number of iterations are definite/fixed is termed as a definite loop.

Dart loops:
Counting loop: for (<Init>;<Condition>;<Update>) <Body>,
Do-While loop: do <Body> while (<Condition>),
While loop: while (<Condition>) <Body>,
For-In loop: for (<Variable> in <list>) <Body>,
Foreach method: <List>.forEach(<Lambda function>).

for loop

The for loop is an implementation of a definite loop. The for loop executes the code block for a specified number of times. It can be used to iterate over a fixed set of values, such as an array

ts
void main() { 
   var num = 5; 
   var factorial = 1; 
   
   for( var i = num ; i >= 1; i-- ) { 
      factorial *= i ; 
   } 
   print(factorial); 
}

for…in Loop

The for...in loop is used to loop through an object's properties.

ts
var obj = [12,13,14]; 
   
   for (var prop in obj) { 
      print(prop); 
   }

Moving on, let’s now discuss the indefinite loops. An indefinite loop is used when the number of iterations in a loop is indeterminate or unknown. Indefinite loops can be implemented using

while Loop

The while loop executes the instructions each time the condition specified evaluates to true. In other words, the loop evaluates the condition before the block of code is executed.

ts
var num = 5; 
var factorial = 1; 

while(num >=1) { 
  factorial = factorial * num; 
  num--; 
} 
print("The factorial  is ${factorial}");

do…while Loop

The do…while loop is similar to the while loop except that the do...while loop doesn’t evaluate the condition for the first time the loop executes.

ts
var n = 10; 
do { 
  print(n); 
  n--; 
}
while(n>=0);

Let us now move on and discuss the Loop Control Statements of Dart.

break Statement

The break statement is used to take the control out of a construct. Using break in a loop causes the program to exit the loop. Following is an example of the break statement.

ts
var i = 1; 
   while(i<=10) { 
      if (i % 5 == 0) { 
         print("The first multiple of 5  between 1 and 10 is : ${i}"); 
         break ;    
         //exit the loop if the first multiple is found 
      } 
      i++; 
   }

continue Statement

The continue statement skips the subsequent statements in the current iteration and takes the control back to the beginning of the loop.

ts
var num = 0; 
var count = 0; 

for(num = 0;num<=20;num++) { 
  if (num % 2==0) { 
     continue; 
  } 
  count++; 
} 
print(" The count of odd values between 0 and 20 is: ${count}");

Exception Handling

In Dart, there are several ways to react to errors that may occur during the runtime of the program.

ts
try <Body> <Catch statements> [finally <Body>]
with <Catch statements> ::= <Catch statement> | <Catch statement> <Catch statements>
and <Catch statement> ::= <how to catch?> <Body>
and <how to catch?> ::= on <Exception> | [ on <Exception> ] catch(<Variable>)
ts
void main() {
int i = 0;
String s = "1";
int d = 3;
try {
  i = int.parse(s) ~/ d;
if (i < 0) {
  throw new TooSmallException();
  }
} on FormatException catch (e) {
  print(e.runtimeType);
} on IntegerDivisionByZeroException {
  print("Division by Zero!");
  rethrow;
} catch(e) {
  rethrow;
} finally {
  print("Ready.");
  }
}

class TooSmallException implements Exception { }

Class

In Dart, the class keyword is used to declare a class. Here is a basic example:

ts
class class_name {  
   <fields> 
   <getters/setters> 
   <constructors> 
   <functions> 
}
ts
class Car {  
  // field 
  String engine = "E1001"; 
  // function 
  void disp() { 
     print(engine); 
  } 
}

Getters and Setters

Getters and setters are special methods that provide read and write access to an object’s properties. Each instance variable of your class has an implicit getter, and a setter if needed. In dart, you can take this even further by implementing your own getters and setters. If you've had any experience in Object-Oriented Programming you'll feel right at home. Here is a basic syntax for a class:

ts
class Person {
  String firstName;
  String lastName;
  double height;
  int personAge;
  int yearofBirth;
  double weight;

  int get age {
    return personAge;
  }

  void set age(int currentYear) {
    personAge = currentYear - yearofBirth;
  }

  // We can also eliminate the setter and just use a getter.
  //int get age {
  //  return DateTime.now().year - yearofBirth;
  //}

  Person({this.firstName,this.lastName,this.personAge,this.yearofBirth,this.weight});
}

We can implement Person class this way:

ts
void main() {
 Person person = Person(firstName:"Thanos",lastName:"Rednos",yearofBirth:1990,weight:200.5);
  print(person.firstName); // output - Thanos
  print(person.lastName); // output - Rednos
  person.age = 2019;
  print(person.age); // output - 29

}

Dart Constructors

A constructor is a special function of the class that is responsible for initializing the variables of the class. Dart defines a constructor with the same name as that of the class. A constructor is a function and hence can be parameterized. However, unlike a function, constructors cannot have a return type. If you don’t declare a constructor, a default no-argument constructor is provided for you.

ts
Class_name(parameter_list) { 
   //constructor body 
}

Named Constructors

Dart provides named constructors to enable a class define multiple constructors. The syntax of named constructors is as given below

ts
Class_name.constructor_name(param_list)

Example

ts
void main() {           
   Car c1 = new Car.namedConst('E1001');                                       
   Car c2 = new Car(); 
}           
class Car {                   
   Car() {                           
      print("Non-parameterized constructor invoked");
   }                                   
   Car.namedConst(String engine) { 
      print("The engine is : ${engine}");    
   }                               
}

The this Keyword

The this keyword refers to the current instance of the class. Here, the parameter name and the name of the class’s field are the same. Hence to avoid ambiguity, the class’s field is prefixed with the this keyword.

ts
void main() { 
   Car c1 = new Car('E1001'); 
}  
class Car { 
   String engine; 
   Car(String engine) { 
      this.engine = engine; 
      print("The engine is : ${engine}"); 
   } 
}

Class Inheritance

Dart supports the concept of Inheritance which is the ability of a program to create new classes from an existing class. The class that is extended to create newer classes is called the parent class/super class. The newly created classes are called the child/sub classes.

A class inherits from another class using the ‘extends’ keyword. Child classes inherit all properties and methods except constructors from the parent class.

Sintax

class child_class_name extends parent_class_name
ts
void main() { 
   var obj = new Circle(); 
   obj.cal_area(); 
}  
class Shape { 
   void cal_area() { 
      print("calling calc area defined in the Shape class"); 
   } 
}  
class Circle extends Shape {}

Types of Inheritance

Single − Every class can at the most extend from one parent class.

Multiple − A class can inherit from multiple classes. Dart doesn’t support multiple inheritance.

Multi-level − A class can inherit from another child class.

Example The following example shows how multi-level inheritance works

ts
void main() { 
   var obj = new Leaf(); 
   obj.str = "hello"; 
   print(obj.str); 
}  
class Root { 
   String str; 
}  
class Child extends Root {}  
class Leaf extends Child {}  
//indirectly inherits from Root by virtue of inheritance

```***Example***
The following example shows how multi-level inheritance works

``` ts
void main() { 
   var obj = new Leaf(); 
   obj.str = "hello"; 
   print(obj.str); 
}  
class Root { 
   String str; 
}  
class Child extends Root {}  
class Leaf extends Child {}  
//indirectly inherits from Root by virtue of inheritance

Class Inheritance and Method Overriding

Method Overriding is a mechanism by which the child class redefines a method in its parent class.

ts
void main() { 
   Child c = new Child(); 
   c.m1(12); 
} 
class Parent { 
   void m1(int a){ print("value of a ${a}");} 
}  
class Child extends Parent { 
   @override 
   void m1(int b) { 
      print("value of b ${b}"); 
   } 
}

The static Keyword

The static keyword can be applied to the data members of a class, i.e., fields and methods. A static variable retains its values till the program finishes execution. Static members are referenced by the class name.

Example

ts
class StaticMem { 
   static int num;  
   static disp() { 
      print("The value of num is ${StaticMem.num}")  ; 
   } 
}  
void main() { 
   StaticMem.num = 12;  
   // initialize the static variable } 
   StaticMem.disp();   
   // invoke the static method 
}

The super Keyword

The super keyword is used to refer to the immediate parent of a class. The keyword can be used to refer to the super class version of a variable, property, or method.

ts
void main() { 
   Child c = new Child(); 
   c.m1(12); 
} 
class Parent { 
   String msg = "message variable from the parent class"; 
   void m1(int a){ print("value of a ${a}");} 
} 
class Child extends Parent { 
   @override 
   void m1(int b) { 
      print("value of b ${b}"); 
      super.m1(13); 
      print("${super.msg}")   ; 
   } 
}

Futures: Async and Await

The async and await keywords provide a declarative way to define asynchronous functions and use their results. Remember these two basic guidelines when using async and await:

  • To define an async function, add async before the function body:
  • The await keyword works only in async functions.
ts
Future<String> login() {
 // Imagine that this function is
 // more complex and slow.
 String userName="Temidjoy";
 return
  Future.delayed(
    Duration(seconds: 4), () => userName);
}

// Asynchronous
main() async {
 print('Authenticating please wait...');
 print(await userName());
}

JSON and serialization

Most mobile and web apps use JSON for tasks such as exchanging data with a web server. With Dart support for JSON serialization and deserialization: converting Dart objects to and from JSON, data exchange is made easy in flutter development.

The following libraries and packages are useful across Dart platform:

  • dart:convert Converters for both JSON and UTF-8 (the character encoding that JSON requires).

  • package:json_serializable An easy-to-use code generation package. When you add some metadata annotations and use the builder provided by this package, the Dart build system generates serialization and deserialization code for you.

  • package:built_value A powerful, opinionated alternative to json_serializable.

You need to serialize and deserialize JSON in your Flutter project? see this example to quickly get started.

Reading and decoding a file

The code snippet below reads a file and runs two transforms over the stream. It first converts the data from UTF8 and then runs it through a LineSplitter. All lines are printed, except any that begin with a hashtag, #.

ts
import 'dart:convert';
import 'dart:io';

Future<void> main(List<String> args) async {
 var file = File(args[0]);
 var lines = utf8.decoder
     .bind(file.openRead())
     .transform(LineSplitter());
 await for (var line in lines) {
   if (!line.startsWith('#')) print(line);
 }
}

Concurrency

Concurrency is the execution of several instruction sequences at the same time. It involves performing more than one task simultaneously.

Dart uses Isolates as a tool for doing works in parallel. The dart:isolate package is Dart’s solution to taking single-threaded Dart code and allowing the application to make greater use of the hard-ware available.

Isolates, as the name suggests, are isolated units of running code. The only way to send data between them is by passing messages, like the way you pass messages between the client and the server. An isolate helps the program to take advantage of multicore microprocessors out of the box.

dart
import 'dart:isolate';  
void foo(var message){ 
   print('execution from foo ... the message is :${message}'); 
}  
void main(){ 
   Isolate.spawn(foo,'Hello!!'); 
   Isolate.spawn(foo,'Greetings!!'); 
   Isolate.spawn(foo,'Welcome!!'); 
   
   print('execution from main1'); 
   print('execution from main2'); 
   print('execution from main3'); 
}