02 Exploring Dart - 3
02 Exploring Dart - 3
Go to the following link to download the setup file and install it using the
setup wizard
https://github.com/GeKorm/dart-windows/releases/download/
v1.6.0/Dart_x64.stable.setup.exe
https://dart.dev/get-dart
Installing Dart SDK: Debian/Ubuntu
Setup
https://dart.dev/get-dart
Installing Dart SDK: Debian/Ubuntu
Modify PATH for access to all Dart binaries
$ export PATH="$PATH:/usr/lib/dart/bin"
To change the PATH for future terminal sessions, use a command like this:
https://dart.dev/get-dart
Installing Dart SDK: Mac
Install Homebrew, and then run:
https://dart.dev/get-dart
A basic Dart program
// Define a function.
printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console.
}
printInteger(int aNumber) {
print('The number is $aNumber.');
}
printInteger(int aNumber) {
print('The number is ${aNumber}.');
}
main()
The special, required, top-level function where app execution starts
main() {
var number = 42;
printInteger(number);
}
Key points about Dart: Objects
Everything you can place in a variable is an object, and every object is an
instance of a class
Top-level functions
printInteger(int aNumber) {
print('The number is $aNumber.');
}
main() {
Both printInteger and main
var number = 42; functions are top-level
printInteger(number); functions inside the
} print_number.dart file
Exercise
Create a dart file named example.dart
Create a top-level function named sum, which accepts two numeric arguments
and returns the sum of the two numbers
dart path/to/example.dart
Key points about Dart: Variables
Dart supports
Top-level variables,
Even variables with numeric types are initially null, because numbers—like
everything else in Dart—are objects
Define a variable of any type and check if its initial value is null
Variables: final and const
A final variable can be set only once
A final top-level or class variable is initialized the first time it’s used
Variables: final and const
Instance variables can be final but not const
const Object i = 3;
const aList = [i as int, 4, 5, 6]; //typecast
const aMap = {if (i is int) i: "int"}; //is and collection if
const aSet = {if (aList is List<int>) ...aList}; //a spread
double
int i = 2;
Built-in types: Numbers
Examples of defining integer literals
int x = 1;
var y = 1.1;
Two strings are equivalent if they contain the same sequence of code units
Exercise
Write a program which prints the contents of the variable s as shown, using
the string interpolation feature. You should use the toUpperCase() method
of the string object to convert the contents of s to all caps.
var s = "Interpolation";
Expected output:
var s1 = '''
You can create
multi-line strings like this one.
''';
Only two objects have type bool: the boolean literals true and false,
which are both compile-time constants.
Built-in types: Lists
In Dart, arrays are List objects, ordered group of objects
Lists use zero-based indexing, where 0 is the index of the first element and
list.length - 1 is the index of the last element
Write a program which declare a list of 10 integers and then print the
first and the last elements.
Built-in types: Lists
To create a list that’s a compile-time constant, add const before the list literal
constantList.add(7);
Built-in types: Lists
Spread operator (...)
you can use the spread operator (...) to insert all the elements of a list
into another list
If the expression to the right of the spread operator might be null, you
can avoid exceptions by using a null-aware spread operator
var list;
What will happen if you try to execute the above code? Check it
Built-in types: Lists
Null-aware spread operator (...?)
If the expression to the right of the spread operator might be null, you
can avoid exceptions by using a null-aware spread operator
var list;
Add the null-aware spread operator as shown above and check if the
exception go away
Built-in types: Lists
collection if
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
What do you think is the length of the nav list?
Built-in types: Lists
collection for
Dart support for sets is provided by set literals and the Set type
You can use is or runtimeType field of the types to check their type
Built-in types: Sets
You can add items to an existing set using the add() or addAll() methods
Write a program which define one set with four elements and another
one with two elements. Add the first set element to the second using
add() or addAll() methods
Each key occurs only once, but you can use the same value multiple times
Dart support for maps is provided by map literals and the Map type
Built-in types: Maps
var weekDays1 = { var weekDays2 = {
'first': 'Monday', 1: 'Monday',
'second': 'Tuesday', 2: 'Tuesday',
'third': 'Wednesday', 3: 'Wednesday',
'fourth': 'Thursday', 4: 'Thursday',
'fifth': 'Friday' 5: 'Friday'
}; };
Write a program that print the second element from each map
Built-in types: Maps
var weekDays = {};
weekDays['first'] = 'Monday';
weekDays[2] = 'Tuesday';
weekDays[3] = 3;
Do you think this code is correct? If yes, check its runtimeType and justify
your answer and restrict both the keys and values only to String type
Built-in types: Maps
Use .length to get the number of key-value pairs in the map
To create a map that’s a compile-time constant, add const before the map
literal
bool isEven(int i) {
return i % 2 == 0;
}
Though not recommended, you can omit the types
isEven(i) {
return i % 2 == 0;
}
Functions
The => expr syntax is a shorthand for { return expr; }
The required parameters are listed first, followed by any optional parameters
main() {
enableFlags(bold:true);
}
main() {
enableFlags(hidden: false, bold:true);
}
Functions
Named parameters
To use the @required annotation, you need to import the meta package
as shown below
import ‘package:meta/meta.dart’;
To know how to import packages check the Import Dart Packages slide
Functions
Positional parameters
And here’s an example of calling this function with the third parameter
Your function can use = to define default values for both named and
positional parameters
Your function can use = to define default values for both named and
positional parameters
bool boldFlag;
bool hiddenFlag;
void enableFlags({bool bold = false, @required bool hidden})
{
boldFlag = bold;
hiddenFlag = hidden;
}
Functions
Default parameter values
Write a program which accept two numbers as command line argument and
returns their sum
Functions as first-class objects
You can pass a function as a parameter to another function
print(element*element);
Try the function you have created with another function which print the word
‘Hello’
Functions as first-class objects
You can also assign a function to a variable
void main() {
print(makeAllCaps('hello'));
}
makeAllCaps variable is assigned anonymous function
Anonymous functions
You can create a nameless function called an anonymous function, or
sometimes a lambda or closure
codeBlock;
};
Anonymous functions
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
You can “follow the curly braces outwards” to see if a variable is in scope
Functions: Lexical scope
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
print(topLevel);
print(insideMain);
print(insideFunction);
print(insideNestedFunction);
}
}
}
Functions: Lexical closures
A closure is a function object that has access to variables in its lexical scope,
even when the function is used outside of its original scope
void main() {
var add2 = makeAdder(2); // Create a function that adds 2
var add4 = makeAdder(4); // Create a function that adds 4
print(add2(3));
print(add4(3));
}
Functions: Return values
All functions return a value
as Typecast
If you aren’t sure that the object is of type T, then use is T to check the type
before using the object
if (emp is Person) {
// Type check
emp.firstName = 'Mr X';
}
Assignment operators
You can assign values using the = operator
To assign only if the assigned-to variable is null, use the ??= operator
// Assign value to a
a = value;
If expr1 is non-null, returns its value; otherwise, evaluates and returns the
value of expr2
expr1 ?? expr2
Conditional expressions
When you need to assign a value based on a boolean expression, consider
using ?:
for loops
Separate even integers from odd integers and place them in separate lists
Write different version of the above program using for, for-in, forEach
method of a list, while, do-while loops for iterating
Control flow statements: Exercise
Write a program which
assert(urlString.startsWith('https'),
Methods do not declare which exceptions they might throw, and you are not
required to catch any exceptions
Dart programs can throw any non-null object—not just Exception and
Error objects—as an exception
Exceptions: Throw
Here’s an example of throwing, or raising, an exception
void main() {
try {
throw StateError('Thrown exception');
} on StateError {
print("Bad State exception has been thrown");
}
}
Exceptions: Catch
To handle code that can throw more than one type of exception, you can
specify multiple catch clauses
The first catch clause that matches the thrown object’s type handles the
exception
If the catch clause does not specify a type, that clause can handle any type of
thrown object
Exceptions: Catch
void main() {
int x, y, z;
try {
z = x + y;
} on NullThrownError { // A specific exception
print('Null exception');
} on Exception catch (e) { // Anything else that is an exception
print('Unknown exception: $e');
} catch (e) { // No specified type, handles all
print('Something really unknown: $e');
}
}
Exceptions: Catch
As the preceding code shows, you can use either on or catch or both
Use catch when your exception handler needs the exception object
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
Exceptions: rethrow
To partially handle an exception, while allowing it to propagate, use the
rethrow keyword
void misbehave() {
try {
dynamic x = true;
print(x++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
Exceptions: Catch
Call the misbehave function in the previous slide and print the rethrown
exception
Exceptions: Finally
To ensure that some code runs whether or not an exception is thrown, use a
finally clause
try {
// some code
} finally {
// Always clean up, even if an exception is thrown.
}
Exceptions: Finally
The finally clause runs after any matching catch clauses
try {
// some code
} catch (e) {
print('Error: $e');
} finally {
// Always clean up, even if an exception is thrown.
}
Classes
Dart is an object-oriented language with classes and mixin-based
inheritance
Every object is an instance of a class, and all classes descend from Object
Mixin-based inheritance means that although every class (except for Object)
has exactly one superclass, a class body can be reused in multiple class
hierarchies
When you call a method, you invoke it on an object: the method has access to
that object’s functions and data
Point(this.x, this.y);
num distanceTo(Point p) {
return sqrt(pow((x - p.x), 2) + pow((y - p.y), 2));
}
@override
String toString() {
return "(${this.x}, ${this.y})";
}
}
Classes: Example
class Point {
num x;
Instance variables/fields/properties
num y;
num distanceTo(Point p) {
return sqrt(pow((x - p.x), 2) + pow((y - p.y), 2));
}
@override
String toString() {
return "(${this.x}, ${this.y})";
} Instance Methods
}
Classes: Using class members
void main() {
var p1 = Point(2, 2);
var p2 = Point(4, 4);
num distance = p1.distanceTo(p2);
print("Distance b/n P1 = ${p1} & P2 = ${p2} is $distance");
p1.x = -2;
p1.y = -3;
distance = p1.distanceTo(p2);
print("Distance b/n P1 = ${p1} & P2 = ${p2} is $distance");
}
Classes: Using class members
Use ?. instead of . to avoid an exception when the leftmost operand is null
void main() {
Point p;
p.x = 3;
p.y = 4;
print(p);
}
Classes: Using class members
Use ?. instead of . to avoid an exception when the leftmost operand is null
void main() {
Point p;
p.x = 3;
Exeption will be thrown here
p.y = 4;
print(p);
}
Classes: Using class members
Use ?. instead of . to avoid an exception when the leftmost operand is null
void main() {
Point p;
p?.x = 3;
No Exeption if you use ?.
p?.y = 4;
print(p);
}
Classes: Using constructors
You can create an object using a constructor
Point(this.x, this.y);
Point.fromMap(Map<String, num> m){
this.x = m['x'];
this.y = m['y'];
} Named constructor
}
Classes: Using constructors
void main() {
Point p0 = Point(0,0);
Point p1 = Point.fromMap({'x': 7, 'y': 2});
print(p0);
print(p1);
}
Classes: Using constructors
Some classes provide constant constructors
class Point {
final num x;
final num y;
const Point(this.x, this.y);
}
Note: The fields are final
Classes: Using constructors
To create a compile-time constant using a constant constructor, put the const
keyword before the constructor name
void main() {
var p = const Point(0,0);
print(p.runtimeType);
}
Classes: Default constructors
If you don’t declare a constructor, a default constructor is provided for you
A subclass that declares no constructors has only the default (no argument,
no name) constructor
Classes: Invoking a superclass constructor
By default, a constructor in a subclass calls the superclass’s unnamed,
no-argument constructor
Specify the superclass constructor after a colon (:), just before the constructor
body (if any)
class Employee extends Person {
Employee() : super.fromJson(defaultData);
// ···
}
Classes: Initializer list
Besides invoking a superclass constructor, you can also initialize instance
variables before the constructor body runs
Write a class to represent a circle with a given radius value and its area.
The area should be computed with a getter method. There should be a
setter for the radius. The setter make sure that the radius is never less
than 0.
Abstract classes
abstract class Shape {
num area();
}
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
void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
class SmartTelevision extends Television {
} void turnOn() {
// ··· super.turnOn();
} _bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
Overriding members
Subclasses can override instance methods, getters, and setters
You can use the @override annotation to indicate that you are intentionally
overriding a member
< + | [] > / ^
>= * << == – %
Overridable operators
For example, if you define a Vector class, you might define a + method to add
two vectors
class Vector {
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
}
Overridable operators
For example, if you define a Vector class, you might define a + method to add
two vectors
void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}
Overridable operators
If you override ==, you should also override Object’s hashCode getter
Extension methods
Extension methods are a way to add functionality to existing libraries
Enumerated types
Often called enumerations or enums, are a special kind of class used to
represent a fixed number of constant values
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
Enumerated types
To get a list of all of the values in the enum, use the enum’s values constant
assert(colors[2] == Color.blue);
Enumerated types
You can use enums in switch statements, and you’ll get a warning if you don’t
handle all of the enum’s values
switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // Without this, you see a WARNING.
print(aColor); // 'Color.blue'
}
Enumerated types
Enumerated types have the following limits
If you want your mixin to be usable as a regular class, you can use the class
keyword instead of mixin
To use a mixin, use the with keyword followed by one or more mixin names
mixins
mixin Sound {
var loudness;
}
Static variables (class variables) are useful for class-wide state and constants
class Queue {
} assert(Queue.capacity == 16);
}
Class variables and methods
Static methods (class methods) do not operate on an instance, and thus do
not have access to this
class Point {
num x, y;
Point(this.x, this.y);
static num distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
Class variables and methods
Static methods (class methods) do not operate on an instance, and thus do
not have access to this
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
}
Generics
Example: List<E>
The <…> notation marks List as a generic (or parameterized) type—a type
that has formal type parameters
You add <type> for lists and sets or <keyType, valueType> for maps
before the opening bracket
Generics
var names = <String>['Seth', 'Kathy', 'Lars'];
'index.html': 'Homepage',
};
Libraries and visibility
The import and library directives can help you create a modular and
shareable code base
Libraries not only provide APIs, but are a unit of privacy: identifiers that start
with an underscore (_) are visible only inside the library
import 'dart:math';
For built-in libraries, the URI has the special dart: scheme
For other libraries, you can use a file system path or the package: scheme
For example, if library1 and library2 both have an Element class, then you
might have code like this
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// Uses Element from lib1.
Element element1 = Element();
// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
Importing only part of a library
If you want to use only part of a library, you can selectively import the library
name: example
dependencies:
meta: ^1.1.8
Using Dart Packages
You can get installation information and the version number from the
https://pub.dev/packages/
Once you have a pubspec, you can run pub get command from the top
directory of your application to get the packages