Structure & Interpretation With Object Oriented Design
Structure & Interpretation With Object Oriented Design
INTERPRETATION
ITH OBJECT
ORIENTED DESIGN
Sanjoy
Kumar
Structure & Interpretation With Object Oriented
Design
Author
Sanjoy Kumar
BSC Engineering(4Th Year)
Electrical & Electronic Engineering
[email protected]
www.iamsanjoy.wordpress.com
Page | 1
Contents
Dart Overview .............................................................................................................................................. 6
The Dart Technologies.................................................................................................................................. 8
Dart Environmental Setups .......................................................................................................................... 9
Windows Operating System.................................................................................................................. 9
Mac OS X 10.10....................................................................................................................................... 9
Ubuntu 14.10 ......................................................................................................................................... 10
Running Dart............................................................................................................................................... 10
Dart Background......................................................................................................................................... 11
Data Type .................................................................................................................................................... 12
Numbers ............................................................................................................................................. 12
Strings .................................................................................................................................................. 13
Boolean................................................................................................................................................ 13
List and Map ...................................................................................................................................... 13
The Dynamic Type........................................................................................................................... 13
Variables ..................................................................................................................................................... 14
Get Started with Hello world ..................................................................................................................... 14
Execute a Dart Program ............................................................................................................... 15
Via the Terminal .......................................................................................................................... 15
Comment In Dart ........................................................................................................................................ 16
Example........................................................................................................................................... 16
String & String Interpolation ...................................................................................................................... 16
String Interpolation ....................................................................................................................... 16
String Properties ............................................................................................................................. 17
Constant...................................................................................................................................................... 18
Loops In Dart Programming ....................................................................................................................... 18
Example: Label with Break ..................................................................................................... 18
If Else Staement ...................................................................................................................................... 19
While Loop .................................................................................................................................................. 20
Operators In Dart ....................................................................................................................................... 21
Types of Operators in Dart .......................................................................................................... 21
There are total of eight types of operators are there in Dart. ......................................................... 21
Arithmetic Operator ............................................................................................................................... 21
Page | 2
Relational Operator................................................................................................................................ 22
Equality Operator ................................................................................................................................... 22
Type Test Operator................................................................................................................................. 23
Assignment Operator ............................................................................................................................. 23
Logical Operator...................................................................................................................................... 23
Logical operators are used to combine two or more conditions. ............................................... 23
Conditional Expression ........................................................................................................................... 24
Switch Case ............................................................................................................................................. 24
Converting Data.......................................................................................................................................... 25
Break Keyword ........................................................................................................................................... 26
Continuous Keyword ................................................................................................................................... 27
Function In Dart .......................................................................................................................................... 28
Optional Positional Parameter ................................................................................................................. 29
Guiding principles .............................................................................................................................. 29
Optional named Parameter ....................................................................................................................... 30
Optional Default Parameter ...................................................................................................................... 31
The Operator ‘==’ ....................................................................................................................................... 32
Exception Handeling................................................................................................................................... 33
A brief introduction to error .................................................................................................................. 33
Class And Object ......................................................................................................................................... 35
From a programming point of view .............................................................................................. 36
Accessing Properties and Methods Of Class ........................................................................ 36
Constructor ................................................................................................................................................. 38
Getter And Setter ....................................................................................................................................... 39
Inheritance .................................................................................................................................................. 41
The getters and setters can also be placed after the constructor. Now let's create a class and
instantiate it. ............................................................................................................................................ 42
Method Overriding ..................................................................................................................................... 42
Method Overriding and its Rules .............................................................................................. 42
Why overriding method must have the same name and same argument list ...... 44
Why overriding method must have the same or covariant return type ................. 44
Why overriding method must not have a more restrictive access modifier ......... 44
Why overriding method may have less restrictive access modifier......................... 45
Page | 3
Why overriding method must not throw new or broader checked exceptions ... 45
Why overriding method may throw narrower checked exceptions or any
unchecked exception ..................................................................................................................... 45
Inheritance With Constructors................................................................................................................... 46
Abstract Class Method ............................................................................................................................... 47
Interface...................................................................................................................................................... 49
Implementing Multiple Interface ............................................................................................................ 50
Static Method Variable .............................................................................................................................. 52
Lambda Function ........................................................................................................................................ 54
Higher Order Function................................................................................................................................ 55
Lexical Closures .......................................................................................................................................... 56
Fixed Length List ......................................................................................................................................... 57
Dart List Example ................................................................................................................................ 58
Growable List .............................................................................................................................................. 59
Map And Hashmap ..................................................................................................................................... 60
Map ....................................................................................................................................................... 61
HashMap............................................................................................................................................. 61
LinkedHashMap .............................................................................................................................. 61
SplayTreeMap ................................................................................................................................... 61
Initialization...................................................................................................................................... 61
Add/Update Value........................................................................................................................... 61
Get Value by Key .............................................................................................................................. 62
Get Map Size ...................................................................................................................................... 62
Check Key Existance ...................................................................................................................... 62
Check Value Existance .................................................................................................................. 62
Remove a Key .................................................................................................................................... 62
Remove by Criteria ......................................................................................................................... 62
Set And HashSet ......................................................................................................................................... 65
Set .......................................................................................................................................................... 66
HashSet ............................................................................................................................................... 66
LinkedHashSet ................................................................................................................................. 66
SplayTreeSet ..................................................................................................................................... 66
Initialization...................................................................................................................................... 66
Page | 4
Add Value ............................................................................................................................................. 66
Get Value at Index .............................................................................................................................. 66
Get first element ................................................................................................................................. 66
Get Last Element ................................................................................................................................ 66
Get SetSize ......................................................................................................................................... 67
Check Value Existance ..................................................................................................................... 67
Check Value By Custom Logic ....................................................................................................... 67
Remove Value ..................................................................................................................................... 67
Remove Value with Custom Logic ................................................................................................ 67
Intersection Between Two Sets ..................................................................................................... 67
Difference Between Two Sets ........................................................................................................ 67
Union of Two Sets ........................................................................................................................... 67
Iterate Through a Set ........................................................................................................................ 67
Map a Set ............................................................................................................................................. 68
Reduce a Set ....................................................................................................................................... 68
Clear all Values ................................................................................................................................... 68
Convert Set to List ........................................................................................................................... 68
Usage Examples ...................................................................................................................................... 69
Callable Class .............................................................................................................................................. 72
Properties ............................................................................................................................................. 73
Methods .................................................................................................................................................. 73
Operators............................................................................................................................................ 73
Dart Libraries ....................................................................................................................................... 74
Dart Package ............................................................................................................................................... 75
Installing a Package ................................................................................................................................ 76
Dart Programming Async ........................................................................................................................... 76
Example ............................................................................................................................................ 77
Dart Future .................................................................................................................................... 77
Restful Web API With Dart ........................................................................................................................ 78
So what's Aqueduct? ...................................................................................................................... 78
What is a Router?........................................................................................................................................ 79
So, how do I apply this? .................................................................................................................... 80
HTTPControllers .......................................................................................................................................... 81
Page | 5
Mocking our datasource ............................................................................................................................. 83
Refactoring the solution............................................................................................................................. 84
Create a ManagedContext .......................................................................................................................... 86
Build our database schema ......................................................................................................................... 87
The test harness .......................................................................................................................................... 88
Configure the database............................................................................................................................... 89
Set up the testing database ........................................................................................................................ 90
Create an Author model............................................................................................................................. 92
Amend the tests ......................................................................................................................................... 93
Dart Language Behind Flutter & Fuchsia OS.............................................................................................. 95
Ways to Run the Dart Code..................................................................................................................... 96
Through Transcompile to JavaScript...................................................................................................... 97
Through DartVM ......................................................................................................................... 97
Through the AOT compilation process .................................................................................................. 97
SnapShots: For faster code execution ....................................................................................................... 98
Script SnapShots ......................................................................................................................... 98
Full SnapShots.............................................................................................................................. 98
Build a chat application .............................................................................................................................. 98
Mark up our HTML page ......................................................................................................................... 99
Implement browser logic for sign-in flow ............................................................................................. 100
Implement a Router class for handling view transition ...................................................................... 107
Create a WebSocket object ................................................................................................................. 108
References ................................................................................................................................................ 109
Dart Overview
Dart is a class-based, single-inheritance, pure object-oriented programming language.
Dart is optionally typed (19) and supports reified generics. The runtime type of every
object is represented as an instance of class Type which can be obtained by calling the
getter runtimeType declared in class Object, the root of the Dart class hierarchy.
Page | 6
However, tools may choose to support execution of some programs with errors. For
instance, a compiler may compile certain constructs with errors such that a dynamic
error will be raised if an attempt is made to execute such a construct, or an IDE
integrated runtime may support opening an editor window when such a construct is
executed, allowing developers to correct the error. It is expected that such features
would amount to a natural extension of the dynamic semantics of Dart as specified here,
but, as mentioned, this specification makes no attempt to specify exactly what that
means.
1. Reified type information reflects the types of objects at run time and may always
be queried by dynamic typechecking constructs (the analogs of instanceOf, casts,
typecase etc. in other languages). Reified type information includes access to instances
of class Type representing types, the run-time type (aka class) of an object, and the
actual values of type parameters to constructors and generic function invocations.
2. Type annotations declare the types of variables and functions (including methods
and constructors).
3. Type annotations may be omitted, in which case they are generally filled in with
the type dynamic (19.7).
A future version of this specification will also specify type inference. Dart programs are
organized in a modular fashion into units called libraries (18).
Libraries are units of encapsulation and may be mutually recursive. However they are
not first class. To get multiple copies of a library running simultaneously, one needs to
spawn an isolate. A dart program execution may occur with assertions enabled or
disabled. The method used to enable or disable assertions is implementation specific.
Page | 7
The Dart Technologies
The following technologies are all part of your journey into the Dart language.
Dart
Dart is a powerful new language out of Google that enables you to use a single language
to target the many facets of a modern web application architecture. Dart ships with a
comprehensive SDK that, when paired with the Pub task runner and Pub package
manager, will empower you and your team to quickly develop enterprise-level
applications for both the web and mobile devices.
IDEA
JetBrains IDEA Community Edition is an open-source IDE. It has a powerful Dart
plugin
that provides everything from syntax highlighting and test runners to debuggers and
code
analysis.
Angular
Angular is a development framework for building mobile and desktop applications. This
book focuses on Angular Dart 2.0. This super-heroic web framework will give you a solid
foundation for front-end development using Dart.
Pub
Pub is versatile task runner that ships with the Dart SDK. Pub offers developers a
standard
way to execute a wide range of common tasks, ranging from starting local web servers
and
acquiring third-party packages to managing version history and running a plethora of
custom preprocessors and transformers.
MongoDB
The Dart community has access to a fantastic project named mongo_dart, which
enables
the Dart runtime to communicate directly with MongoDB. MongoDB is a document-
store
style of a NoSQL database that supports a Dart-centric approach to structuring project
data.
Page | 8
Dart Environmental Setups
The Dart SDK binaries should be part of your system’s default environment path. If you
are not using a package manager, you will need to add the file system location of the
dart-sdk folder to your existing environmental variables. Each operating system
variant has a different way to persist environment variables; the following sections
contain
a few recommendations.
Page | 9
2. Open a new command-line session, and execute the following code in the terminal:
$ dart —version
Note
You need the root password to launch the nano editor for this file.
3. In the nano editor, append the following new colon-delimited value to the end of the
existing path string:
Click here to view code image
:/Users/USER_HOME/dart-sdk/bin
4. Run the following command:
$ source /etc/environment
5. Open a new command-line session, and execute the following code in the terminal:
Running Dart
One of the compelling aspects of Dart is its ability to execute code on multiple platforms.
You can run your libraries as server code, as client code, or on mobile. Let’s take a look
at
a few different ways to get your code up and running.
Command-line Applications
Command-line applications run the Dart VM as a headless process on a server. In this
case, the server is your local development workstation. Let’s take a look at how to launch
your application through the IDEA.
Page | 10
1. Open IntelliJ IDEA.
2. Select File > New Project, or click Create New Project on the Welcome splash
screen.
3. On the left panel, select Dart.
4. Enter the following values in the New Project dialog
5. Select the Generate Sample Content checkbox.
6. Select the Console Application entry in the list of sample content.
7. Click Next, and enter the following values:
Project Name: dart_console_temp
Project Location: /Users/USER_HOME/projects/dart_console_temp
IntelliJ will generate a project scaffold that will be visible in the Projects panel in a
folder named dart_console_temp. This scaffold will contain all the files
needed to run a command-line Dart application. Let’s go ahead and run it.
8. In the window bar, select Run > Edit Configurations.
9. Click the plus icon, and select Dart Command Line App.
10. Name the new configuration DartConsole.
11. Click the ellipses button to the right of the Dart File field, and find bin/main.dart in
the active project.
12. Click the ellipses button to the right of the Working Directory field, and select the
folder dart_console_temp.
13. Click OK to save, and close your configuration.
14. In the top menu bar, choose Run > Run ‘DartConsole’.
Dart Background
Productive
Dart’s syntax is clear and concise, its tooling simple yet powerful. Sound typing
helps you to identify subtle errors early. Dart has battle-hardened core
libraries and an ecosystem of thousands of packages
Fast
Dart provides optimizing ahead-of-time compilation to get predictably high
performance and fast startup across mobile devices and the web.
Portable
Dart compiles to ARM and x86 code, so that Dart mobile apps can run natively on
iOS, Android, and beyond. For web apps, Dart compiles to JavaScript.
Page | 11
Approachable
Dart is familiar to many existing developers, thanks to its unsurprising object
orientation and syntax. If you already know C++, C#, or Java, you can be
productive with Dart in just a few days.
Reactive
Dart is well-suited to reactive programming, with support for managing short-
lived objects—such as UI widgets—through Dart’s fast object allocation and
generational garbage collector. Dart supports asynchronous programming through
language features and APIs that use Future and Stream objects.
Since its inception, Dart has gone through different phases as Google tried to sell its
potential to developers. Google has rebuilt it’s advertising service AdSense with Dart.
That demonstrate’s Google’s commitment to Dart by depending on the language for it’s
main method of generating revenue.
The language also has many great features like garbage collection and a strong typing
system (as of Dart 2.0). All of it sits on top of a VM like Java, which allows there to be
less configuration between the test side and the source code. A programmer can just get
started from the get-go!
Data Type
One of the most fundamental characteristics of a programming language is the set of data
types it supports. These are the type of values that can be represented and manipulated
in a programming language.
The Dart language supports the following types−
Numbers
Strings
Booleans
Lists
Maps
Numbers
Numbers in Dart are used to represent numeric literals. The Number Dart come in two
flavours −
Integer − Integer values represent non-fractional values, i.e., numeric values
without a decimal point. For example, the value "10" is an integer. Integer literals
are represented using the int keyword.
Double − Dart also supports fractional numeric values i.e. values with decimal
points. The Double data type in Dart represents a 64-bit (double-precision)
Page | 12
floating-point number. For example, the value "10.10". The keyword double is
used to represent floating point literals.
Strings
Strings represent a sequence of characters. For instance, if you were to store some data
like name, address etc. the string data type should be used. A Dart string is a sequence of
UTF-16 code units. Runes are used to represent a sequence of UTF-32 code units.
The keyword String is used to represent string literals. String values are embedded in
either single or double quotes.
Boolean
The Boolean data type represents Boolean values true and false. Dart uses
the bool keyword to represent a Boolean value.
List and Map
The data types list and map are used to represent a collection of objects. A List is an
ordered group of objects. The List data type in Dart is synonymous to the concept of an
array in other programming languages. The Map data type represents a set of values as
key-value pairs. The dart: core library enables creation and manipulation of these
collections through the predefined List and Map classes respectively.
The Dynamic Type
Dart is an optionally typed language. If the type of a variable is not explicitly specified,
the variable’s type is dynamic. The dynamic keyword can also be used as a type
annotation explicitly.
Page | 13
21. print(score);
22. print(exponents);
23.
24. // NOTE: All data types in Dart are Objects.
25. // Therefore, their initial value is by default 'null'
26. }
Variables
A variable is “a named space in the memory” that stores values. In other words, it acts a
container for values in a program. Variable names are called identifiers. Following are
the naming rules for an identifier −
Identifiers cannot be keywords.
Identifiers can contain alphabets and numbers.
Identifiers cannot contain spaces and special characters, except the underscore
(_) and the dollar ($) sign.
Variable names cannot begin with a number.
In order to implement Hello World in Dart, developers need to understand only three
concepts like main methods, strings, and arrow functions. But look at the code above, it
seems deceptively easy, right?
Page | 14
What is going on is “main()” only does one thing, print the phrase “Hello, World!”. We’ll
dig into how and why all of this happens in a bit. But it’s important to step away for a bit
and just look at what’s there and acknowledge how simple it is.
1. void main() {
2.
3. // This is my first line of code
4. print("Hello World"); // this is another comment ....
5.
6. print("This is my first application");
7.
8. // Performing arithematic operation
9. print(12 / 4);
10.
11. // Printing out boolean value
12. print(false);
13. }
The main() function is a predefined method in Dart. This method acts as the entry point
to the application. A Dart script needs the main() method for execution. print() is a
predefined function that prints the specified string or value to the standard output i.e.
the terminal.
The output of the above code will be −
Hello World!
Page | 15
Comment In Dart
Comments are a way to improve the readability of a program. Comments can be used to
include additional information about a program like author of the code, hints about a
function/ construct etc. Comments are ignored by the compiler.
Dart supports the following types of comments −
Single-line comments ( // ) − Any text between a "//" and the end of a line is
treated as a comment
Multi-line comments (/* */) − These comments may span multiple lines.
Example
/* This is a
Multi-line comment
*/
The String data type represents a sequence of characters. A Dart string is a sequence of
UTF 16 code units.
String values in Dart can be represented using either single or double or triple quotes.
Single line strings are represented using single or double quotes. Triple quotes are used
to represent multi-line strings.
The syntax of representing string values in Dart is as given below –
String Interpolation
The process of creating a new string by appending a value to a static string is termed
as concatenation or interpolation. In other words, it is the process of adding a string
to another string.
The operator plus (+) is a commonly used mechanism to concatenate / interpolate
strings.
Page | 16
4. int score = 23;
5. var count = 23; // It is inferred as integer automatically by compiler
6. int hexValue = 0xEADEBAEE;
7.
8. // Numbers: double
9. double percentage = 93.4;
10. var percent = 82.533;
11. double exponents = 1.42e5;
12.
13. // Strings
14. String name = "Henry";
15. var company = "Google";
16.
17. // Boolean
18. bool isValid = true;
19. var isAlive = false;
20.
21. print(score);
22. print(exponents);
23.
24. // NOTE: All data types in Dart are Objects.
25. // Therefore, their initial value is by default 'null'
26. }
String Properties
The properties listed in the following table are all read-only.
1 codeUnits
2 isEmpty
3 Length
Returns the length of the string including space, tab and newline characters.
Page | 17
Constant
For Constant
1. void main() {
2.
3. // final
4. final cityName = 'Mumbai';
5. // name = 'Peter'; // Throws an error
6.
7. final String countryName = 'India';
8.
9. // const
10. const PI = 3.14;
11. const double gravity = 9.8;
12. }
13.
14. class Circle {
15.
16. final color = 'Red';
17. static const PI = 3.14;
18. }
1. void main() {
2. outerloop: // This is the label name
3.
4. for (var i = 0; i < 5; i++) {
5. print("Innerloop: ${i}");
6. innerloop:
7.
Page | 18
8. for (var j = 0; j < 5; j++) {
9. if (j > 3 ) break ;
10.
11. // Quit the innermost loop
12. if (i == 2) break innerloop;
13.
14. // Do the same thing
15. if (i == 4) break outerloop;
16.
17. // Quit the outer loop
18. print("Innerloop: ${j}");
19. }
20. }
21. }
If Else Staement
If the Boolean expression evaluates to be true, then the block of code inside the if
statement will be executed.
If the Boolean expression evaluates to be false, then the else’s code block will be
executed.
Here remember that else is optional here.
1. void main() {
2.
3. // IF and ELSE Statements
4. var salary = 15000;
5.
6. if (salary > 20000) {
7. print("You got promotion. Congratulations !");
8. } else {
9. print("You need to work hard !");
10. }
11.
12. // IF ELSE IF Ladder statements
13. var marks = 70;
14.
15. if (marks >= 90 && marks < 100) {
16. print("A+ grade");
17. } else if (marks >= 80 && marks < 90) {
18. print("A grade");
19. } else if (marks >= 70 && marks < 80) {
20. print("B grade");
21. } else if (marks >= 60 && marks < 70) {
22. print("C grade");
23. } else if (marks > 30 && marks < 60) {
Page | 19
24. print("D grade");
25. } else if (marks >= 0 && marks < 30) {
26. print("You have failed");
27. } else {
28. print("Invalid Marks. Please try again !");
29. }
30. }
So now I think you get the basic idea about if-else in the dart. If-else is not much
more different then other languages. If you have previous programming experience
then maybe you’ll feel right at home at this moment.
Share your thoughts on the dart and if I miss something, please let me know. I’ll
happy to lear it from you. Till then Keep Loving, Keep Coding. I’ll surely catch
you up in another article.
While Loop
That’s it for do-while loop guys. Feel free to share with me if I miss something I will love
to learn it from you.
Remember no teacher, no book, no video tutorial, or no blog can teach you everything.
As one said Learning is Journey and Journey never ends. Just collect some data from
here and there, read it, learn it, practice it, and try to apply it. Don’t feel hesitate that
you can’t do that or you don’t know this concept or that concept. Remember every
programmer was passed from the path on which you are walking right now. Remember
Every Master was Once a Beginner. Work hard and Give your best.
Till Then Keep Loving, Keep Coding. And just like always I’ll surely catch you up in the
next article.
1. void main() {
2.
3. // WHILE Loop
4. // WAP to find the even numbers between 1 to 10
Page | 20
5.
6. var i = 1;
7. while (i <= 10) {
8.
9. if (i % 2 == 0) {
10. print(i);
11. }
12.
13. i++;
14. }
15. }
Operators In Dart
Every expression is composed of two parts:
Arithmetic Operator
There are nine types of an arithmetic operator are there in a dart.
Page | 21
Relational Operator
Relational operator shows the relation between the two operands.
The relational operator can have only two values either true or false.
There are four relational operators are there.
Equality Operator
Equality operator checks whether two objects are equal or not.
Same as relational operator they contain Boolean value either true or false.
There are two equality operators are there.
Here remember that two strings are equivalent only if they contain the same character
sequence. Here the sequence of character is important rather than the number of
character.
Page | 22
void main() {
var a = "Jay";
var b = "Jya"; //If here value is Jay then this is true
print(a == b);
}
Output
false
Assignment Operator
Dart has main two assignment operator.
Here note that (+=, -=, *=, /=) are also a type of assignment operator. But as they
are just a shortcut way. I didn’t mention them.
Logical Operator
Logical operators are used to combine two or more conditions.
Logical operators return a Boolean value of true or false.
There are three logical operators are there:
Page | 23
Conditional Expression
1. void main() {
2.
3. // Conditional Expressions
4.
5. // 1. condition ? exp1 : exp2
6. // If condition is true, evaluates expr1 (and returns its value);
7. // otherwise, evaluates and returns the value of expr2.
8.
9. int a = 2;
10. int b = 3;
11.
12. int smallNumber = a < b ? a : b;
13. print("$smallNumber is smaller");
14.
15.
16.
17. // 2. exp1 ?? exp2
18. // If expr1 is non-null, returns its value; otherwise, evaluates and
19. // returns the value of expr2.
20.
21. String name = null;
22.
23. String nameToPrint = name ?? "Guest User";
24. print(nameToPrint);
25. }
Switch Case
A switch statement is an alternative of else if statements which allows a
variable to be tested for equality against a list of values.
Each value is called a case, and the variable being switched on is checked for each
switch case.
Wherever an expression value matches with a case value, the body of that case will
be executed.
The switch will be terminated using a break statement. Here break statement is
compulsory. Otherwise, the dart analysis engine will throw a syntax error.
Only for the default case break is optional. Otherwise, in all cases break is
compulsory.
1. void main() {
2.
3.
Page | 24
4. // Switch Case Statements: Applicable for only 'int' and 'String'
5.
6.
7. String grade = 'A';
8.
9.
10. switch (grade) {
11.
12.
13. case 'A':
14. print("Excellent grade of A");
15. break;
16.
17.
18. case 'B':
19. print("Very Good !");
20. break;
21.
22.
23. case 'C':
24. print("Good enough. But work hard");
25. break;
26.
27.
28. case 'F':
29. print("You have failed");
30. break;
31. default:
32. print("Invalid Grade");
33. }
34. }
Converting Data
A well-known example illustrating the benefits of realtime open data is Transport for
London and the ‘Citymapper effect’. Deloitte estimates that the 13,000 developers who
started using this data created 600+ apps (including Citymapper), contributing £130m
to the city’s economy within just a few years of the scheme’s launch. So it’s surprising
large-scale examples like this are so rare (if you know of any similar success stories/
Page | 25
good sources of realtime data please comment at the end of this article). The EU’s data
commission has also noted a distinct lack of publicly available, value-generating data
sources (think traffic data, weather information, realtime financial updates) due to the
costs involved of realtime distribution. In the UK, the Office of National Statistics (the
ONS) has noted a widespread lack of data sources in realtime. Headlines aside, ask most
developers and you’ll get the same answer.
By allowing developers to publish and consumer realtime open data feeds on Ably’s API
Streamer (a realtime API Management Platform) Ably’s Open Data Streaming Program
aims to make public realtime data easier to work with. Work setting this in motion has
involved identifying the most useful, publicly-available realtime data, converting it to a
single realtime feed, and inputting it to the Ably Hub, which then re-distributes it to
users (for free) in whichever realtime protocol and data structure they need. The process
brought us into contact with hundreds of ‘open’ realtime data sets, and we soon became
veterans in identifying and solving common problems developers experience when
trying to consume realtime data feeds. Recurring obstacles range from a lack of ‘real’
realtime information, to a lack of protocol support, to heterogeneous data structures.
Below we isolate three key potential problems to bear in mind when accessing ‘realtime’ data
sources, and share what we learnt about how to overcome them.
1. import 'dart:convert';
2. void main() {
3. var jsonString = """
4. {
5. "cats": {
6. "abysinnian": {
7. "origin": "Burma",
8. "behavior": "playful"
9. }
10. }
11. }
12. """;
13. var obj = JSON.decode(jsonString);
14. print(obj['cats']['abysinnian']['behavior']); // playful
15. }
Break Keyword
If we want to go out of a loop then we use a break statement. If we use a break statement in a
loop then execution will continue with the immediate next statement outside the loop. After a
break, all the remaining statements in the loop are skipped. The break statement can be used in
Page | 26
a while loop, for loop, do-while loop, and in a switch case.
Syntax :
if(condition)
{
break;
}
1. void main() {
2.
3.
4. // BREAK keyword
5. // Using Labels
6. // Nested FOR Loop
7.
8.
9. myOuterLoop: for (int i = 1; i <= 3; i++) {
10.
11.
12. innerLoop: for (int j = 1; j <= 3; j++) {
13. print("$i $j");
14.
15.
16. if (i == 2 && j == 2) {
17. break myOuterLoop;
18. }
19. }
20. }
21. }
Continuous Keyword
The continue keyword is used mainly with loops. When we do not want to execute some
statements then we use a continue statement to skip those statements to execute. If the
continue statement is confronted in the program then it will start the next iteration. It
does not terminate the loop, it just skips some part of the loop. The execution again
starts from the top of the loop. In some ways it is similar to the break statement.
Syntax :
if(condition)
{
continue;
}
1. void main() {
2.
Page | 27
3. // CONTINUE keyword
4. // Using Labels
5.
6. myLoop: for (int i = 1; i <= 3; i++) {
7.
8. myInnerLoop: for (int j = 1; j <= 3; j++) {
9.
10. if (i == 2 && j == 2) {
11. continue myLoop;
12. }
13. print("$i $j");
14. }
15. }
16. }
Function In Dart
Functions are the building blocks of readable, maintainable, and reusable code. A
function is a set of statements to perform a specific task. Functions organize the program
into logical blocks of code. Once defined, functions may be called to access code. This
makes the code reusable. Moreover, functions make it easy to read and maintain the
program’s code.
A function declaration tells the compiler about a function's name, return type, and
parameters. A function definition provides the actual body of the function.
1. // OBJECTIVES
2. // 1. Define a Function
3. // 2. Pass parameters to a Function
4. // 3. Return value from a Function
5. // 4. Test that by default a Function returns null
6.
7. void main() {
8.
9. findPerimeter(4, 2);
10.
11. int rectArea = getArea(10, 5);
12. print("The area is $rectArea");
13. }
14.
15. void findPerimeter(int length, int breadth) {
16.
17. int perimeter = 2 * (length + breadth);
18. print("The perimeter is $perimeter");
19. }
20.
21. int getArea(int length, int breadth) {
22.
Page | 28
23. int area = length * breadth;
24. return area;
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.
When we write functions, it's common to want to give the user options to suit a range of
use-cases. There are good ways and bad ways of doing it, and this post is going to
explore them.
Guiding principles
Page | 29
We'll use these principles to help us understand good and bad design decisions in our
case study.
1. // 1. Required Parameters
2. // 2. Optional Positional Parameters
3.
4. void main() {
5.
6. printCities("New York", "New Delhi", "Sydney");
7. print("");
8.
9. printCountries("USA"); // You can skip the Optional Positional Parameters
10.
11. }
12.
13. // Required Parameters
14. void printCities(String name1, String name2, String name3) {
15.
16. print("Name 1 is $name1");
17. print("Name 2 is $name2");
18. print("Name 3 is $name3");
19. }
20.
21. // Optional Positional Parameters
22. void printCountries(String name1, [String name2, String name3]) {
23.
24. print("Name 1 is $name1");
25. print("Name 2 is $name2");
26. print("Name 3 is $name3");
27. }
Page | 30
12.
13. print("Length is $length");
14. print("Breadth is $breadth");
15. print("Height is $height");
16.
17. print("Volume is ${length * breadth * height}");
18. }
In this example we're using the name and the surname as required parameters. And the
secondName as named parameter and in case nothing is passed to it the value will be
an empty string.
As you can see the named parameter should be included inside the parentheses.
In case we need to have a function with only named parameters all we need to do is
to surround all the parameter section in the function signature with curly braces.
Page | 31
The output of the second case is 5 because num1 takes the value of 4
and num2 has the value of 1, thanks to our handy default parameter.
Omitted Values
You may be thinking at this point .. “What happens if you want to make the first
parameter a default parameter? What do you do then?” Well, that is what we will
be discussing in this section and it is new knowledge for me too.
When we come across a case where we would like to create a default parameter as
our first parameter, or even one of the middle parameters, we need to make use
of the keyword undefined. When passing in arguments to our
function, undefined should be used as a placeholder.
• Every instance of type int and String has a primitive operator ‘==’.
• Every instance of type Symbol which was originally obtained by evaluation of a literal
symbol or a constant invocation of a constructor of the Symbol class has a primitive
operator ‘==’.
• Every instance of type Type which was originally obtained by evaluating a constant
type literal (19.2) has a primitive operator ‘==’.
• An instance o has a primitive operator ‘==’ if the dynamic type of o is a class C, and C
has a primitive operator ‘==’.
• A class C has a primitive operator ‘==’ if it does not have an implementation of the
operator ‘==’ that overrides the one inherited from Object. In particular, the following
have a primitive operator ‘==’: The null object (16.4), function objects obtained by
function closurization of a static method or a top-level function (16.18), instances of type
bool (16.6), and instances obtained by evaluation of a list literal (16.9), a map literal
(16.10), or a set literal (16.11). When we say that the operator ‘==’ of a given instance or
class is not prim- itive, it means that it is not true that said instance or class has a
primitive operator ‘==’.
Page | 32
Exception Handeling
This article explains what exception handling is and how it differs from
traditional error handling with error codes. The article does not get
into usage or exception classes, but only to explain their purpose.
From the dawn of programming, error codes have been used to deal with errors in
applications. An error code is used to indicate if the
executed function was successful or not.
Page | 33
33. } catch (e, s) {
34. print("The exception thrown is $e");
35. print("STACK TRACE \n $s");
36. }
37.
38. print(""); print("CASE 4");
39. // CASE 4: Whether there is an Exception or not, FINALLY Clause is always Executed
40. try {
41. int result = 12 ~/ 3;
42. print("The result is $result");
43. } catch (e) {
44. print("The exception thrown is $e");
45. } finally {
46. print("This is FINALLY Clause and is always executed.");
47. }
48.
49. print(""); print("CASE 5");
50. // CASE 5: Custom Exception
51. try {
52. depositMoney(-200);
53. } catch (e) {
54. print(e.errorMessage());
55. } finally {
56. // Code
57. }
58. }
59.
60. class DepositException implements Exception {
61. String errorMessage() {
62. return "You cannot enter amount less than 0";
63. }
64. }
65.
66. void depositMoney(int amount) {
67. if (amount < 0) {
68. throw new DepositException();
69. }
70. }
The example illustrates that when you use error codes, it is the API
consumer that must abort if something fails. You might, but how about
the rest of the team, or those who maintained the application before
you? It is like you would retire the entire police force and expect
all citizens to behave and be good law abiding citizens.
The problem is that the code looks perfectly legal, but silently ignores
errors. If you for instance mistakenly add a white space after all
account names on the account selection page, the code above starts to
fail silently. What's worse is that you will not know about it until
Page | 34
code dependent upon the default account starts to fail, and that can be
after a while. Tracking down that subsequent error can be challenging,
primarily if the default account is set in different ways.
1.
2. void main() {
3.
4. var student1 = Student(); // One Object, student1 is reference variable
5. student1.id = 23;
6. student1.name = "Peter";
7. print("${student1.id} and ${student1.name}");
8.
9. student1.study();
10. student1.sleep();
11.
12. var student2 = Student(); // One Object, student2 is reference variable
13. student2.id = 45;
14. student2.name = "Sam";
15. print("${student2.id} and ${student2.name}");
16. student2.study();
17. student2.sleep();
18. }
19.
Page | 35
20. // Define states (properties) and behavior of a Student
21. class Student {
22. int id = -1; // Instance or Field Variable, default value is -1
23. String name; // Instance or Field Variable, default value is null
24.
25. void study() {
26. print("${this.name} is now studying");
27. }
28.
29. void sleep() {
30. print("${this.name} is now sleeping");
31. }
32. }
1. // Accessing properties
2. myMobile.color;
3. myMobile.brandName;
Page | 36
4.
5. // Accessing methods
6. myMobile.calling();
7. myMobile.musicPlay();
8. Let’s understand all concepts by one complete program
9. class Mobile {
10. String color; // Property
11. String brandName;
12. String modelName;
13.
14. String calling() { // Method Creation
15. return "Mobile can do calling";
16. }
17.
18. String musicPlay() {
19. return "Mobile can play Music";
20. }
21.
22. String videoPlay() {
23. return "Mobile can play video";
24. }
25. }
26.
27. main() {
28. var myMobile = new Mobile(); // Creating Object
29.
30. myMobile.color = "White"; // Accessing Class's Property
31. myMobile.brandName = "Apple Inc.";
32. myMobile.modelName = "iPhone 14";
33.
34. print(myMobile.color);
35. print(myMobile.modelName);
36. print(myMobile.brandName);
37. print(myMobile.calling());
38. print(myMobile.musicPlay());
39. print(myMobile.videoPlay());
40. }
41.
42. Output
43. White
44. iPhone 14
45. Apple Inc.
46. Mobile can do calling
47. Mobile can play Music
48. Mobile can play video
Remember guys, classes and objects are basic building blocks of Object-Oriented
Programming.
Page | 37
All big frameworks like Flutter, React, Django, Angular and big software
like IDEs, Web Apps, Mobile Apps, Server side apps and also programming
language itself are based on OOPs concepts.
So please have a clear clarity and strong understanding of these concepts.
Remember no teacher, no book, no video tutorial, or no blog can teach you everything.
As one said Learning is Journey and Journey never ends. Just collect some data from
here and there, read it, learn it, practice it, and try to apply it. Don’t feel hesitate that
you can’t do that or you don’t know this concept or that concept. Remember every
programmer was passed from the path on which you are walking right now. Remember
Every Master was Once a Beginner. Work hard and Give your best.
Constructor
1. // Objectives
2. // 1. Default Constructor
3. // 2. Parameterized Constructor
4. // 3. Named Constructor
5. // 4. Constant Constructor
6.
7. void main() {
8.
9. var student1 = Student(23, "Peter"); // One Object, student1 is reference variable
10. print("${student1.id} and ${student1.name}");
11.
12. student1.study();
13. student1.sleep();
14.
15. var student2 = Student(45, "Sam"); // One Object, student2 is reference variable
16. print("${student2.id} and ${student2.name}");
17.
18. student2.study();
19. student2.sleep();
20.
21.
22. var student3 = Student.myCustomConstructor(); // One object, student3 is a referenc
e variable
23. student3.id = 54;
24. student3.name = "Rahul";
25. print("${student3.id} and ${student3.name}");
26.
27.
28. var student4 = Student.myAnotherNamedConstructor(87, "Paul");
29. print("${student4.id} and ${student4.name}");
30. }
31.
32. // Define states (properties) and behavior of a Student
Page | 38
33. class Student {
34. int id = -1;
35. String name;
36.
37. Student(this.id, this.name); // Parameterised Constructor
38.
39. Student.myCustomConstructor() { // Named Constructor
40. print("This is my custom constructor");
41. }
42.
43. Student.myAnotherNamedConstructor(this.id, this.name); // Named Constructor
44.
45. void study() {
46. print("${this.name} is now studying");
47. }
48.
49. void sleep() {
50. print("${this.name} is now sleeping");
51. }
52. }
Remember no teacher, no book, no video tutorial, or no blog can teach you everything.
As one said Learning is Journey and Journey never ends. Just collect some data from
here and there, read it, learn it, practice it, and try to apply it. Don’t feel hesitate that
you can’t do that or you don’t know this concept or that concept. Remember every
programmer was passed from the path on which you are walking right now. Remember
Every Master was Once a Beginner. Work hard and Give your best.
A getter declaration may conflict with other declarations (10.10). In particular, a getter
can never override a method, and a method can never override a getter or an instance
variable. The rules for when a getter correctly overrides another member are given
elsewhere .
Page | 39
Setters are functions (9) that are used to set the values of object properties.
hsetterSignaturei ::= htypei
The instance setters of a class C are those instance setters declared by C either implicitly
or explicitly, and the instance setters inherited by C from its superclass. The static
setters of a class C are those static setters declared by
We could enforce this via the grammar, but we’d have to specify the evaluation rules in
that case. It is a static warning if a setter declares a return type other than void. It is a
static warning if a class has a setter named v= with argument type T and a getter named
v with return type S, and S may not be assigned to T. The rules for when a setter
correctly overrides another member are given elsewhere . A setter declaration may
conflict with other declarations as well (10.10).
1. // Objectives
2. // 1. Default Getter and Setter
3. // 2. Custom Getter and Setter
4. // 3. Private Instance Variable
5.
6. void main() {
7.
8. var student = Student();
9. student.name = "Peter"; // Calling default Setter to set value
10. print(student.name); // Calling default Getter to get value
11.
12. student.percentage = 438.0; // Calling Custom Setter to set value
13. print(student.percentage); // Calling Custom Getter to get value
14. }
15.
16. class Student {
17.
18. String name; // Instance Variable with default Getter and Setter
19.
20. double _percent; // Private Instance Variable for its own library
21.
22. // Instance variable with Custom Setter
Page | 40
23. void set percentage(double marksSecured) => _percent = (marksSecured / 500) * 10
0;
24. // Instance variable with Custom Getter
25. double get percentage => _percent;
26. }
Inheritance
1. // Objectives
2. // 1. Exploring Inheritance
3.
4. void main() {
5.
6. var dog = Dog();
7. dog.breed = "Labrador";
8. dog.color = "Black";
9. dog.bark();
10. dog.eat();
11.
12. var cat = Cat();
13. cat.color = "White";
14. cat.age = 6;
15. cat.eat();
16. cat.meow();
17.
18. var animal = Animal();
19. animal.color = "brown";
20. animal.eat();
21. }
22.
23. class Animal {
24.
25. String color;
26.
27. void eat() {
28. print("Eat !");
29. }
30. }
31.
32. class Dog extends Animal { // Dog is Child class or sub class, Animal is super or par
ent class
33.
34. String breed;
35.
36. void bark() {
37. print("Bark !");
38. }
39. }
Page | 41
40.
41. class Cat extends Animal { // Cat is Child class or sub class, Animal is super or pare
nt class
42.
43. int age;
44.
45. void meow() {
46. print("Meow !");
47. }
48. }
The getters and setters can also be placed after the constructor. Now let's create a class
and instantiate it.
1. class Vehicle {
2. String make;
3. String model;
4. int manufactureYear;
5. int vehicleAge;
6. String color;
7.
8. int get age {
9. return vehicleAge;
10. }
11.
12. void set age(int currentYear) {
13. vehicleAge = currentYear - manufactureYear;
14. }
15.
16. // We can also eliminate the setter and just use a getter.
17. //int get age {
18. // return DateTime.now().year - manufactureYear;
19. //}
20.
21. Vehicle({this.make,this.model,this.manufactureYear,this.color,});
22. }
Method Overriding
Method Overriding and its Rules
Page | 42
Overriding means redefining a behaviour (method) again in the child class which was
already defined by its parent class but to do so overriding method in the child class must
follow certain rules and guidelines.
With respect to the method it overrides, the overriding method must follow the
following rules.
To understand these reasons properly let's consider below example where we have a
class Mammal which defines readAndGet method which is reading some file and
returning an instance of class Mammal.
Class Human extends class Mammal and overrides readAndGet method to return the
instance of Human instead of an instance of Mammal.
1. // Objectives
2. // 1. Exploring Method Overriding
3.
4. void main() {
5.
6. var dog = Dog();
7. dog.eat();
8.
9. print(dog.color);
10. }
11.
12. class Animal {
13.
14. String color = "brown";
15.
16. void eat() {
17. print("Animal is eating !");
18. }
19. }
20.
21. class Dog extends Animal {
22.
23. String breed;
24.
25. String color = "Black"; // Property Overriding
26.
27. void bark() {
28. print("Bark !");
29. }
30.
31. // Method Overriding
32. void eat() {
33. print("Dog is eating !");
34. super.eat();
35. print("More food to eat");
Page | 43
36. }
37. }
Why overriding method must have the same name and same argument list
Well conceptually mammal is pointing to an object of class Human and we are
calling readAndGet method on mammal, so to get this call resolved at
runtime Human should also have a method readAndGet. And if Human has inherited
that method from Mammal then there is no problem but if Human is
overriding readAndGet, it should provide the same method signature as provided
by Mammal because the method has been already got called according to that method
signature.
But you may be asking how it is handled physically from vtables so I must tell you that,
JVM creates a vtable for every class and when it encounters an overriding method it
keeps the same method name (Mammal.readAndGet()) while just update the memory
address for that method. So both overridden and overriding method must have the same
method and argument list.
Why overriding method must have the same or covariant return type
So we know, for compiler the method is getting called from class Mammal and for JVM
call is from the instance of class Human but in both cases, readAndGet method call must
return an object which can be assigned to obj. And since obj is of the type Mammal it
can either hold an instance of Mammal class or an instance of a child class
of Mammal (child of Mammal are covariant to Mammal).
And this why having a different return type is not allowed by the compiler in the first
place.
Why overriding method must not have a more restrictive access modifier
The same logic is applicable here as well, call to readAndGet method will be resolved at
runtime and as we can see readAndGet is public in class Mammal, now suppose.
In both cases, the code will compile successfully because for compiler readAndGet is
getting called from class Mammal but in both cases, JVM will not be able
to access readAndGet from Human because it will be restricted.
Page | 44
So to avoid this uncertainty, assigning restrictive access to the overriding method in the
child class is not allowed at all.
So making the overriding method less restrictive cannot create any problem in the
future and that's it is allowed.
Because for compiler the method is getting called from Mammal, so the compiler will
force us to handle only IOException but at runtime we know method will be
throwing Exception which is not getting handled and our code will break if the method
throws an exception.
That's why it is prevented at the compiler level itself and we are not allowed to throw
any new or broader checked exception because it will not be handled by JVM at the end.
And that's why overriding methods are allowed to throw narrower checked and other
unchecked exceptions.
Page | 45
Inheritance With Constructors
Inheritance is a paradigm in programming languages that allows objects to share traits
similarly to how a human child inherits a trait from a parent. If a father has green eyes,
his son might inherit that trait. If a daughter has blonde hair, one of her parents or
grandparents contributed the gene, allowing her to inherit the blonde hair.
So far you’ve learned about the structure of a single class. Being a classical language,
Dart supports single inheritance on a class-by-class basis. Single inheritance means that
a class can directly inherit from only one class at a time.
You’ve already been using implicit inheritance. If no extended class is defined, all
classes in Dart automatically extend the class Object. Dart implements inheritance when
the extends keyword is placed after the class name declaration followed by a named
identifier of the class which is to be inherited from.
Over the next few sections, you’re going to define the taxonomy of a fleet of flying
vehicles. You’ll start with the most generic and work your way to the most specific.
1. // Objectives
2. // 1. Inheritance with Default Constructor and Parameterised Constructor
3. // 2. Inheritance with Named Constructor
4.
5. void main() {
6.
7. var dog1 = Dog("Labrador", "Black");
8.
9. print("");
10.
11. var dog2 = Dog("Pug", "Brown");
12.
13. print("");
14.
15. var dog3 = Dog.myNamedConstructor("German Shepherd", "Black-Brown");
16. }
17.
18. class Animal {
19.
20. String color;
21.
22. Animal(String color) {
Page | 46
23. this.color = color;
24. print("Animal class constructor");
25. }
26.
27. Animal.myAnimalNamedConstrctor(String color) {
28. print("Animal class named constructor");
29. }
30. }
31.
32. class Dog extends Animal {
33.
34. String breed;
35.
36. Dog(String breed, String color) : super(color) {
37. this.breed = breed;
38. print("Dog class constructor");
39. }
40.
41. Dog.myNamedConstructor(String breed, String color) : super.myAnimalNamedConst
rctor(color) {
42. this.breed = breed;
43. print("Dog class Named Constructor");
44. }
45. }
1. // Objectives
2. // 1. Abstract Method
3. // 2. Abstract Class
4.
5. void main() {
6.
7. // var shape = Shape(); // Error. Cannot instantiate Abstract Class
8.
9. var rectangle = Rectangle();
10. rectangle.draw();
11.
12. var circle = Circle();
13. circle.draw();
14. }
15.
16. abstract class Shape {
Page | 47
17.
18. // Define your Instance variable if needed
19. int x;
20. int y;
21.
22. void draw(); // Abstract Method
23.
24. void myNormalFunction() {
25. // Some code
26. }
27. }
28.
29.
30. class Rectangle extends Shape {
31.
32. void draw() {
33. print("Drawing Rectangle.....");
34. }
35. }
36.
37. class Circle extends Shape {
38.
39. void draw() {
40. print("Drawing Circle.....");
41. }
42. }
In the implementation from Example 4.16, on the line with new Aircraft(), there is now
an error: 'Abstract classes cannot be created with a 'new' expression'. To fix this, let’s
create some concrete implementations of Aircraft:
Page | 48
20. //--Turns Off—
Interface
The interface defines the syntax that any class must follow. Interface mostly used
to apply compulsion on class.
When any class implements an Interface then it must override every method and
instance variable of an interface.
However, Dart does not have a syntax for declaring interfaces. The class
declaration is themselves interface in a dart.
Any class can be act as an interface. Classes can use implements keyword to use
any class as an interface.
Once any class is used as interface then it is mandatory to override each and every
method and instance variable of that class. In simple words, a class must redefine
every method and instance variable of the interface.
1. // Objectives
2. // 1. Interface
3.
4. void main() {
5.
6. var tv = Television();
7. tv.volumeUp();
8. tv.volumeDown();
9. }
10.
11. class Remote {
12.
13. void volumeUp() {
14. print("______Volume Up from Remote_______");
15. }
16.
17. void volumeDown() {
18. print("______Volume Down from Remote_______");
19. }
20. }
21.
22. class AnotherClass {
23.
24. void justAnotherMethod(){
25. // Code
26. }
27.
28. }
29.
30. // Here Remote and AnotherClass acts as Interface
31. class Television implements Remote, AnotherClass {
Page | 49
32.
33. void volumeUp() {
34. // super.volumeUp(); // Not allowed to call super while implementing a class as In
terface
35. print("______Volume Up in Television_______");
36. }
37.
38. void volumeDown() {
39. print("______Volume Down in Television_______");
40. }
41.
42. void justAnotherMethod() {
43. print("Some code");
44. }
45. }
1. class Person {
2. String name;
3.
4. void ShowName() {
5. print("My name is $name");
6. }
7.
8. void walk() {
9. print("Person can walk");
10. }
11.
12. void talk() {
13. print("Person can talk");
14. }
15. }
16.
17. class Viveki {
18. String profession;
19.
20. void ShowProfession() {
21. print("from class Viveki my profession is $profession");
22. }
23. }
24.
25. class Jay implements Person, Viveki {
26. @override
Page | 50
27. String profession;
28.
29. @override
30. void ShowProfession() {
31. print("from class Jay my Profession is $profession");
32. }
33. @override
34. String name;
35.
36. @override
37. void ShowName() {
38. print("From class Jay my name is $name");
39. }
40.
41. @override
42. void walk() {
43. print("Jay can walk");
44. }
45.
46. @override
47. void talk() {
48. print("Jay can talk");
49. }
50. }
51.
52. main() {
53. Person person = new Person();
54. Jay jay = new Jay();
55. Viveki viveki = new Viveki();
56.
57. person.walk();
58. person.talk();
59. person.name = "Person";
60. person.ShowName();
61.
62. print("");
63.
64. jay.walk();
65. jay.talk();
66. jay.name = "JAY";
67. jay.profession = "Software Development";
68. jay.ShowProfession();
69. jay.ShowName();
70.
71. print("");
72.
73. viveki.profession = "Chemical Engineer";
74. viveki.ShowProfession();
75. }
76.
77. Output
Page | 51
78.
79. Person can walk
80. Person can talk
81. My name is Person
82.
83. Jay can walk
84. Jay can talk
85. from class Jay my Profession is Software Development
86. From class Jay my name is JAY
87.
88. from class Viveki my profession is Chemical Engineer
So that’s it for interface guys. Please read this article twice if you don’t understand the
concept in the first move. And do a little bit of research on an interface. Don’t worry if
you didn’t get the concept in the first attempt. Even I get it in a 3rd try. So don’t worry,
just practice it.
Also, feel free to let me know if I miss something. Till then keep Loving, keep Coding.
And I’ll surely catch you up in next article.
Remember no teacher, no book, no video tutorial, or no blog can teach you everything.
As one said Learning is Journey and Journey never ends. Just collect some data from
here and there, read it, learn it, practice it, and try to apply it. Don’t feel hesitate that
you can’t do that or you don’t know this concept or that concept. Remember
every programmer was passed from the path on which you are walking right now.
Remember Every Master was Once a Beginner. Work hard and Give your best.
Static methods & variables are variables whose declarations are immediately contained
within a class declaration and that are declared static.
Page | 52
1. // Objectives
2. // 1. Static Methods and Variables
3.
4. void main() {
5.
6. var circle1 = Circle();
7. // circle1.pi; // 4 bytes
8.
9. var circle2 = Circle();
10. // circle2.pi; // 4 bytes
11.
12. // 8 bytes // waste of extra 4 bytes
13.
14. Circle.pi; // 4 bytes
15. Circle.pi; // No more memory will be allocated .
16.
17.
18. // circle.calculateArea();
19.
20. // print(Circle.pi); // Syntax to call Static Variable
21.
22. // Circle.calculateArea(); // Syntax to call Static Method
23. }
24.
25. class Circle {
26.
27. static const double pi = 3.14;
28. static int maxRadius = 5;
29.
30. String color;
31.
32. static void calculateArea() {
33. print("Some code to calculate area of Circle");
34. // myNormalFunction(); // Not allowed to call instance functions
35. // this.color; // You cannot use 'this' keyword and even cannot access Instance
variables
36. }
37.
38. void myNormalFunction() {
39. calculateArea();
40. this.color = "Red";
41. print(pi);
42. print(maxRadius);
43. }
44. }
Example
1. class StringUtils {
2. static String removeUnderscores(String string) {
3. return string.replaceAll("_", " ");
Page | 53
4. }
5.
6. static int countAs(String string) {
7. int total = string.length;
8. int diff = string.replaceAll("A", "").length;
9. return total - diff;
10. }
11. }
12.
13. void main() {
14. print(StringUtils.removeUnderscores("I_went_to_the_store.")); // I went to the store.
15.
16. print(StringUtils.countAs("Apple abe Able Mable Arc At")); // 4
17. }
Lambda Function
But here remember that by using Lambda function’s syntax you can only return one
expression. It must be only one line expression. Just like normal function lambda
function cannot have a block of code to execute.
In short, if your function has only one expression to return then to quickly represent
it in just one line you can use lambda function.
1. // Objectives
2. // 1. Lambda Functions
3. // NOTE: A function in Dart is object
4.
5. void main() {
6.
7. // Defining Lambda: 1st way
8. Function addTwoNumbers = (int a, int b) {
9. var sum = a + b;
10. print(sum);
11. };
12.
13. var multiplyByFour = (int number) {
14. return number * 4;
15. };
16.
Page | 54
17. // Defining Lambda: 2nd way: Function Expression: Using Short Hand Syntax or FAT
Arrow ( '=>' )
18. Function addNumbers = (int a, int b) => print(a + b);
19.
20. var multiplyFour = (int number) => number * 4;
21.
22.
23. // Calling lambda function
24. addTwoNumbers(2, 5);
25. print(multiplyByFour(5));
26.
27. addNumbers(3, 7);
28. print(multiplyFour(10));
29. }
30.
31.
32. // A example of Normal function
33. void addMyNumbers(int a, int b) {
34.
35. var sum = a + b;
36. print(sum);
37. }
That’s it for lambda functions guys. Please play around with this concept for some time.
Also, Feel free to let me know if I miss something. Till Then keep Loving, Keep Coding.
And I’ll surely catch you up in next article.
Remember no teacher, no book, no video tutorial, or no blog can teach you everything.
As one said Learning is Journey and Journey never ends. Just collect some data from
here and there, read it, learn it, practice it, and try to apply it. Don’t feel hesitate that you
can’t do that or you don’t know this concept or that concept. Remember every
programmer was passed from the path on which you are walking right now. Remember
Every Master was Once a Beginner. Work hard and Give your best.
1. // Objectives
2. // 1. Higher-Order Function:
3. // How to pass function as parameter?
4. // How to return a function from another function?
5.
6.
7. void main() {
8.
9. // Example One: Passing Function to Higher-Order Function
10. Function addNumbers = (a, b) => print(a + b);
11. someOtherFunction("Hello", addNumbers);
Page | 55
12.
13.
14. // Example Two: Receiving Function from Higher-Order Function
15. var myFunc = taskToPerform();
16. print(myFunc(10)); // multiplyFour(10) // number * 4 // 10 * 4 // OUT
PUT: 40
17. }
18.
19.
20.
21. // Example one: Accepts function as parameter
22. void someOtherFunction(String message, Function myFunction) { // Higher-
Order Function
23.
24. print(message);
25. myFunction(2, 4); // addNumbers(2, 4) // print(a + b); // print(2 + 4) // OU
TPUT: 6
26. }
27.
28.
29. // Example two: Returns a function
30. Function taskToPerform() { // Higher-Order Function
31.
32. Function multiplyFour = (int number) => number * 4;
33. return multiplyFour;
34. }
Lexical Closures
Functions can close over variables defined in surrounding scopes
1. // Objective
2. // 1. Closures
3.
4.
5. void main() {
6.
7. // Definition 1:
8. // A closure is a function that has access to the parent scope, even after the scope has c
losed.
9.
10. String message = "Dar is good";
Page | 56
11.
12. Function showMessage = () {
13. message = "Dart is awesome";
14. print(message);
15. };
16.
17. showMessage();
18.
19.
20. // Definition 2:
21. // A closure is a function object that has access to variables in its lexical scope,
22. // even when the function is used outside of its original scope.
23.
24. Function talk = () {
25.
26. String msg = "Hi";
27.
28. Function say = () {
29. msg = "Hello";
30. print(msg);
31. };
32.
33. return say;
34. };
35.
36. Function speak = talk();
37.
38. speak(); // talk() // say() // print(msg) // "Hello"
39. }
As you can see from the above example, there are many ways to create a function. A
function that does not define a return type (like using var syntax) has a return type
of dynamic. If parameters in function definition have no types, they implicitly have
the dynamic type.
Page | 57
Dart List Example | Dart Programming List Tutorial is today’s topic. The
Dart List is the ordered group of objects. The dart: core library provides a List class that
enables the creation and manipulation of lists. The very commonly used collection in
programming is an array. Dart represents the arrays in the form of List objects. A
unique number called the index identifies each element in the List. An index starts
from zero and extends up to n-1 where n is a total number of items in the List.
1. // Objectives
2. // 1. Fixed-length list
3.
4. void main() {
5.
6. // Elements: N N N N N
Page | 58
7. // Index: 0 1 2 3 4
8.
9. List<int> numbersList = List(5); // Fixed-length list
10. numbersList[0] = 73; // Insert operation
11. numbersList[1] = 64;
12. numbersList[3] = 21;
13. numbersList[4] = 12;
14.
15. numbersList[0] = 99; // Update operation
16. numbersList[1] = null;// Delete operation
17.
18. print(numbersList[0]);
19. print("\n");
20.
21. // numbersList.remove(73); // Not supported in fixed-length list
22. // numbersList.add(24); // Not supported in fixed-length list
23. // numbersList.removeAt(3); // Not supported in fixed-length list
24. // numbersList.clear(); // Not supported in fixed-length list
25.
26. for (int element in numbersList) { // Using Individual Element (Objects
)
27. print(element);
28. }
29.
30. print("\n");
31.
32. numbersList.forEach((element) => print(element)); // Using Lambda
33.
34. print("\n");
35.
36. for (int i = 0; i < numbersList.length; i++) { // Using Index
37. print(numbersList[i]);
38. }
Growable List
A growable list’s length can change at run-time. The syntax for declaring and initializing
a growable list is as given below −
1. // Objectives
2. // 1. Growable list
3.
4. void main() {
5. // Elements: N 21 12
6. // Index: 0 1 2
7.
8. List<String> countries = ["USA", "INDIA", "CHINA"]; // Growable List : METHOD
1
9. countries.add("Nepal");
Page | 59
10. countries.add("Japan");
11.
12.
13. List<int> numbersList = List(); // Growable List: METHOD 2
14. numbersList.add(73); // Insert Operation
15. numbersList.add(64);
16. numbersList.add(21);
17. numbersList.add(12);
18.
19. numbersList[0] = 99; // Update operation
20. numbersList[1] = null; // Delete operation
21.
22. print(numbersList[0]);
23.
24. numbersList.remove(99);
25. numbersList.add(24);
26. numbersList.removeAt(3);
27. // numbersList.clear();
28.
29. print("\n");
30.
31. for (int element in numbersList) { // Using Individual Element ( Objects )
32. print(element);
33. }
34.
35. print("\n");
36.
37. numbersList.forEach((element) => print(element)); // Using Lambda
38.
39. print("\n");
40.
41. for (int i = 0; i < numbersList.length; i++) { // Using Index
42. print(numbersList[i]);
43. }
44.
45. }
Page | 60
Map
Map is a collection of key/value pairs. In Dart, an entry of a Map is called MapEntry,
which is a key/value pair. Retrieving a value can be done by using key name. Each
entries in a Map can be iterated. The iteration order depends on the
implementation HashMap, LinkedHashMap or SplayTreeMap. If you create an instance
using Map constructor, it will create a LinkedHashMap by default.
HashMap
A HashMap doesn't guarantee insertion order. If you insert an entry with key A and then
another entry with key B, when you iterate through the map, there's a possibility that
you'll get entry B first.
LinkedHashMap
Data stored in a LinkedHashMap is sorted according to insertion order. If you insert an
entry with key A and then another entry with key B, when you iterate through the map,
you'll always get entry A first before entry B.
SplayTreeMap
A SplayTreeMap is a self-balancing binary tree that allows recently accessed elements to
be accessed quicker. Basic operations like insertion, look-up and removal can be done
in O(log(n)). It performs tree rotations by bringing frequently accessed elements close to
the root of the tree. Therefore, if some entries need to be accessed more often than the
others, using SplayTreeMap is a good choice. However, if the data access frequency is
almost the same on all entries, using SplayTreeMap is useless.
Initialization
import 'dart:collection';
main() {
HashMap map1 = new HashMap<int, String>();
LinkedHashMap map2 = new LinkedHashMap<int, String>();
SplayTreeMap map3 = new SplayTreeMap<int, String>();
}
Add/Update Value
The simplest way to add or update the value of a key is by using square brackets. It will
create a new MapEntry if no entry with the key found or update the value if there is an
entry with the key.
map1[1] = 'A';
To add a MapEntry only if an entry with the key doesn't exist in the map,
use putIfAbsent method.
Page | 61
hashMap.update(1, (e) => '${e}A');
The first argument is the key, while the second argument is update function.
The e parameter in the second argument function is the old value. So you can update the
value based on old value, like incrementing the value if it is an integer or concatenating
the old value to produce a new string like the second line of the above example. If you
don't want to use the old value, just ignore it (without removing from the function
argument) like the first line of the above example.
The above code only works if the key is exist. Otherwise, you'll get error. To handle the
case where the key is not exist, add the optional ifAbsent in the third argument, as
exemplified below.
map1[1]
The code above is for getting the value of entry with key 1. If no entry with that key is
found, it will return null.
map1.length
Check Key Existance
To check whether the map contains a certain key, use containsKey method.
map1.containsKey(1)
map1.containsValue('A')
Remove a Key
To remove a key from a map, you can use remove method.
map1.remove(2);
Remove by Criteria
In case you want to remove entries from map with custom logic based on key and/or
value, you can use removeWhere method. The code below is for removing entries whose
key mod 2 equals 0 or whose value is C.
Page | 62
1. // Objectives
2. // 1. Maps
3. // --> KEY has to be unique
4. // --> VALUE can be duplicate
5.
6. void main() {
7.
8. Map<String, int> countryDialingCode = { // Method 1: Using Literal
9. "USA": 1,
10. "INDIA": 91,
11. "PAKISTAN": 92
12. };
13.
14.
15. Map<String, String> fruits = Map(); // Method 2: Using Constructor
16. fruits["apple"] = "red";
17. fruits["banana"] = "yellow";
18. fruits["guava"] = "green";
19.
20. fruits.containsKey("apple"); // returns true if the KEY is present in Map
21. fruits.update("apple", (value) => "green"); // Update the VALUE for the given KE
Y
22. fruits.remove("apple"); // removes KEY and it's VALUE and returns th
e VALUE
23. fruits.isEmpty; // returns true if the Map is empty
24. fruits.length; // returns number of elements in Map
25. // fruits.clear(); // Deletes all elements
26.
27. print(fruits["apple"]);
28.
29. print("\n");
30.
31. for (String key in fruits.keys) { // Print all keys
32. print(key);
33. }
34.
35. print("\n");
36.
37. for (String value in fruits.values) { // Print all values
38. print(value);
39. }
40.
41. print("\n");
42.
43. fruits.forEach((key, value) => print("key: $key and value: $value")); // Using Lambd
a
44.
45. }
Page | 63
With map method, you can map not only the value of each entries, but also the key. For
every entry, you need to return a new MapEntry.
1. import 'dart:collection';
2.
3. main() {
4. HashMap map1 = new HashMap<int, String>();
5. LinkedHashMap map2 = new LinkedHashMap<int, String>();
6. SplayTreeMap map3 = new SplayTreeMap<int, String>();
7.
8. map1[1] = 'A';
9. print('map1: $map1');
10. // Print result:
11. // map1: {1: A}
12.
13. // This should be ignored because entry with key 1 is already exist.
14. map1.putIfAbsent(1, () => 'A2');
15.
16. // This will add entry with key 2 and value B
17. map1.putIfAbsent(2, () => 'B');
18. print('map1: $map1');
19. // Print result: xxx
20. // map1: {1: A, 2: B}
21.
22. print('map1.length: ${map1.length}');
23. // Print result:
24. // map1.length: 2
25.
26. // This will update the value of entry with key 1 by appending 'A' character in the end
27. map1.update(1, (e) => '${e}A', ifAbsent: () => 'A');
28.
29. // This will create a new entry with key 3 and value C
30. map1.update(3, (e) => '${e}C', ifAbsent: () => 'C');
31.
32. print('map1: $map1');
33. // Print result:
34. // map1: {1: AA, 2: B, 3: C}
35.
36. // Retrieve the value of entry with key 1
37. print('Value of 1: ${map1[1]}');
38. // Print result:
39. // Value of 1: AA
40.
Page | 64
41. // This will remove entry with key 2
42. map1.remove(2);
43. print('map1: $map1');
44. // Print result:
45. // map1: {1: AA, 3: C}
46.
47. // This will remove entry whose key mods 2 equals 0 or whose value equals C
48. map1.removeWhere((key, value) => key % 2 == 0 || value == 'C');
49. print('map1: $map1');
50. // Print result:
51. // map1: {1: AA}
52.
53. // Just adding other values
54. map1[4] = 'D';
55. map1[5] = 'E';
56.
57. // Iterate through map entries
58. map1.forEach((key, value) {
59. print('key: $key, value: $value');
60. });
61. // Print result:
62. // key: 1, value: AA
63. // key: 4, value: D
64. // key: 5, value: E
65.
66. var mappedHashMap = map1.map((key, value) {
67. return new MapEntry(key, '$value mapped');
68. });
69. print('mappedHashMap: $mappedHashMap');
70. // Print result:
71. // mappedHashMap: {1: AA mapped, 4: D mapped, 5: E mapped}
72.
73. map1.clear();
74. print('map1: $map1');
75. // Print result:
76. // map1: {}
77. }
Page | 65
Set
A collection of objects in which each object can occur only once. The data type of a Set
can be integer, String, double, Object or any data type. There are three kinds of Set in
Dart, differentiated by how the data stored which affects the iteration of the elements.
By default, if you create a new Set, an instance of LinkedHashSet will be created.
HashSet
HashSet is an unordered hash-table based Set implementation. So, if you insert value A
first and then insert another value B, when you iterate the elements, you may get value
B first before value A. It allows null as element.
LinkedHashSet
In LinkedHashSet, data is stored based on insertion order. So, if you insert value A first
and then insert another value B, when you iterate the elements, you will get value A first
before value B. Like HashSet, it allows null element.
SplayTreeSet
SplayTreeSet is based on a self-balancing tree. Most operations can be done
in O(log(n)). You cannot store non-comparable objects inclduing null. If you need to
access certain elements more frequently than the others, it's beter to use SplayTreeSet as
it can adjust the tree to move frequently accessed elements near the top of the tree.
Initialization
LinkedHashSet set1 = new LinkedHashSet();
Add Value
Adding a new value to a Set is very simple, just use add method. If the value is duplicate
of other elements, it will be ignored.
set1.add('A');
set1.elementAt(2);
set1.first
Page | 66
set1.last
Get SetSize
set1.length
Remove Value
set1.remove('B');
set1.difference(set2);
set1.union(set2);
Iterate Through a Set
For looping through all values, use forEach method.
set1.forEach((value) {
Page | 67
print('Value: $value');
});
Map a Set
It also has map method, you can map each value using your own logic
Reduce a Set
reduce method is provided as well. It accepts a function with the first parameter is the
accumulator and the second parameter is the value of current element.
set1.clear();
1. // Objectives
2. // 1. Sets:
3. // --> Unordered Collection
4. // --> All elements are unique
5.
6. void main() {
7.
8. Set<String> countries = Set.from(["USA", "INDIA", "CHINA"]); // Method 1: From
a list
9. countries.add("Nepal");
10. countries.add("Japan");
11.
12.
13. Set<int> numbersSet = Set(); // Method 2: Using Constructor
14. numbersSet.add(73); // Insert Operation
15. numbersSet.add(64);
16. numbersSet.add(21);
Page | 68
17. numbersSet.add(12);
18.
19. numbersSet.add(73); // Duplicate entries are ignored
20. numbersSet.add(73); // Ignored
21.
22. numbersSet.contains(73); // returns true if the element is found in set
23. numbersSet.remove(64); // returns true if the element was found and deleted
24. numbersSet.isEmpty; // returns true if the Set is empty
25. numbersSet.length; // returns number of elements in Set
26. // numbersSet.clear(); // Deletes all elements
27.
28. print("\n");
29.
30. for (int element in numbersSet) { // Using Individual Element ( Objects )
31. print(element);
32. }
33.
34. print("\n");
35.
36. numbersSet.forEach((element) => print(element)); // Using Lambda
37. }
Usage Examples
Below is the usage examples of Set
1. import 'dart:collection';
2.
3. import 'package:flutter_app/post.dart';
4.
5. main() {
6. LinkedHashSet set1 = new LinkedHashSet<String>();
7. // SplayTreeSet set1 = new SplayTreeSet<String>(); // Uncomment to use SplayTreeSet
Page | 69
21. print('Element at index 2: ${set1.elementAt(2)}');
22. print('First element: ${set1.first}');
23. print('Last element: ${set1.last}');
24. // Print result:
25. // Element at index 2: C
26. // First element: A
27. // Last element: E
28.
29. // Adding the same value shouldn't affect the set
30. set1.add('A');
31. print('set1: $set1');
32. // Print result:
33. // set1: {A, B, C, D, E}
34.
35. // Get number of elements
36. print('Size of set: ${set1.length}');
37. // Print result:
38. // Size of set: 5
39.
40. // Does it contain certain value?
41. print('Contains A? ${set1.contains('A')}');
42. // Print result:
43. // Contains A? true
44.
45. // Using [any] for custom logic
46. // In this example, checks if the set contain any value other than D
47. bool anyValueNotD = set1.any((value) {
48. return value != 'D';
49. });
50. print('anyValueNotD? :$anyValueNotD');
51. // Print result:
52. // anyValueNotD? :true
53.
54. set1.remove('B');
55. print('set1: $set1');
56. // Print result:
57. // set1: {A, C, D, E}
58.
59. set1.removeWhere((value) => value == 'A' || value == 'C');
60. print('set1: $set1');
61. // Print result:
62. // set1: {D, E}
63.
64. // Add values to set 2
65. set2.add('E');
66. set2.add('F');
67.
68. // Get intersection of set1 and set2
69. print('intersection: ${set1.intersection(set2)}');
70. // Print result:
71. // intersection: {E}
Page | 70
72.
73. // Get difference of set1 and set2
74. print('difference: ${set1.difference(set2)}');
75. // Print result:
76. // difference: {D}
77.
78. // Combine set1 with set2
79. print('union: ${set1.union(set2)}');
80. // Print result:
81. // union: {D, E, F}
82.
83. // Map every value
84. var mappedSet = set1.map((value) {
85. return 'mapped $value';
86. });
87. print('mappedSet: $mappedSet');
88. // Print result:
89. // mappedSet: (mapped D, mapped E)
90.
91. // For each loop
92. set1.forEach((value) {
93. print('Value: $value');
94. });
95. // Print result:
96. // Value: D
97. // Value: E
98.
99. var reduceResult = set1.reduce((acc, value) {
100. return '$acc$value';
101. });
102. print('reduceResult: $reduceResult');
103. // Print result:
104. // reduceResult: DE
105.
106. // Convert set to list
107. List<String> listFromSet = set1.toList();
108. print('listFromSet: $listFromSet');
109. // Print result:
110. // listFromSet: [D, E]
111.
112. // Print set as string
113. print('set1 string: ${set1.toString()}');
114. // Print result:
115. // set1 string: {D, E}
116.
117. // Clear set1
118. set1.clear();
119. print('set1: $set1');
120. // Print result:
121. // set1: {}
122. }
Page | 71
Callable Class
An interface functions and mixins that can be invoked from Sass by passing in
arguments.
This extends AsyncCallable because all synchronous callables are also usable in
asynchronous contexts. Callables are usable with both the synchronous and
asynchronous compile() functions, and as such should be used in preference
to AsyncCallables if possible.
When writing custom functions, it's important to make them as user-friendly and as
close to the standards set by Sass's core functions as possible. Some good guidelines to
follow include:
Page | 72
Properties
hashCode → int
read-only, inherited
name → String
The callable's name.
read-only, inherited
runtimeType → Type
A representation of the runtime type of the object.
read-only, inherited
Methods
noSuchMethod(Invocation invocation) → dynamic
inherited
toString() → String
Returns a string representation of this object.
inherited
Operators
operator ==(dynamic other) → bool
inherited
1. // Objectives
2. // 1. Callable class
3. // --> Class treated as Function.
4. // --> Implement call() method
5.
6. void main() {
Page | 73
7.
8. var personOne = Person();
9. var msg = personOne(25, "Peter");
10. print(msg);
11. }
12.
13. class Person {
14.
15. String call(int age, String name) {
16. return "The name of the person is $name and age is $age";
17. }
18. }
Dart Libraries
The import and library directives can help you create a modular and shareable code
base. Every Dart app is a library, even if it doesn’t use a library directive. Libraries can
be distributed using packages. See Pub Package and Asset Manager for information
about pub, a package manager included in the SDK.
1. port 'other.dart';
2. void main() {
3. var b = new B();
4. b.testB();
5. }
6. class B extends A {
7. String _private;
8. testB() {
9. _private = 'Hello';
10. print('String value: $_private'); // Hello
11. testA();
12. print('String value: $_private'); // Hello
13. }
14. }
Specifying a library prefix If you import two libraries that have conflicting identifiers,
then you can specify a prefix for one or both libraries. For example, if library1 and
library2 both have an Element class, then you might have code like this:
1. import 'package:lib1/lib1.dart';
2. import 'package:lib2/lib2.dart' as lib2;
3. // ...
4. var element1 = new Element(); // Uses Element from lib1.
Page | 74
5. var element2 =
6. new lib2.Element(); // Uses Element from lib2.
Lazily loading a library Deferred loading (also called lazy loading) allows an application
to load a library on demand, if and when it’s needed. To lazily load a library, you must
first import it using deferred as
1. library other;
2. class A {
3. int _private = 0;
4. testA() {
5. print('int value: $_private'); // 0
6. _private = 5;
7. print('int value: $_private'); // 5
8. }
9. }
1. library calculator_lib;
2. import 'dart:math';
3.
4. //import statement after the libaray statement
5. int add(int firstNumber,int secondNumber){
6. print("inside add method of Calculator Library ") ;
7. return firstNumber+secondNumber;
8. }
9. int modulus(int firstNumber,int secondNumber){
10. print("inside modulus method of Calculator Library ") ;
11. return firstNumber%secondNumber;
12. }
13. int random(int no){
14. return new Random().nextInt(no);
15. }
Dart Package
A package is a mechanism to encapsulate a group of programming units. Applications
might at times need integration of some third-party libraries or plugins. Every language
has a mechanism for managing external packages like Maven or Gradle for Java, Nuget
for .NET, npm for Node.js, etc. The package manager for Dart is pub.
Page | 75
Pub helps to install packages in the repository. The repository of packages hosted can be
found at https://pub.dartlang.org/.
The package metadata is defined in a file, pubsec.yaml. YAML is the acronym
for Yet Another Markup Language. The pub tool can be used to download all
various libraries that an application requires.
Every Dart application has a pubspec.yaml file which contains the application
dependencies to other libraries and metadata of applications like application name,
author, version, and description.
The contents of a pubspec.yaml file should look something like this −
Installing a Package
Consider an example where an application needs to parse xml. Dart XML is a lightweight
library that is open source and stable for parsing, traversing, querying and building XML
documents.
The steps for achieving the said task is as follows −
1. name: TestApp
2. version: 0.0.1
3. description: A simple console application.
4. #dependencies:
5. # foo_bar: '>=1.0.0 <2.0.0'
6. dependencies: https://mail.google.com/mail/u/0/images/cleardot.gif
7. xml:
The readLineSync() is a synchronous method. This means that the execution of all
instructions that follow the readLineSync() function call will be blocked till
the readLineSync() method finishes execution.
The stdin.readLineSync waits for input. It stops in its tracks and does not execute any
further until it receives the user’s input.
In computing, we say something is synchronous when it waits for an event to happen
before continuing. A disadvantage in this approach is that if a part of the code takes too
long to execute, the subsequent blocks, though unrelated, will be blocked from executing.
Consider a webserver that must respond to multiple requests for a resource.
Page | 76
A synchronous execution model will block every other user’s request till it finishes
processing the current request. In such a case, like that of a web server, every request
must be independent of the others. This means, the webserver should not wait for the
current request to finish executing before it responds to request from other users.
Simply put, it should accept requests from new users before necessarily completing the
requests of previous users. This is termed as asynchronous. Asynchronous programming
basically means no waiting or non-blocking programming model.
The dart:async package facilitates implementing asynchronous programming blocks
in a Dart script.
Example
1. import "dart:async";
2. import "dart:io";
3.
4. void main(){
5. File file = new File( Directory.current.path+"\\data\\contact.txt");
6. Future<String> f = file.readAsString();
7.
8. // returns a futrue, this is Async method
9. f.then((data)=>print(data));
10.
11. // once file is read , call back method is invoked
12. print("End of main");
13. // this get printed first, showing fileReading is non blocking or async
14. }
1. End of main
2. 1, Tom
3. 2, John
4. 3, Tim
5. 4, Jan
The "end of main" executes first while the script continues reading the file.
The Future class, part of dart:async, is used for getting the result of a computation
after an asynchronous task has completed. This Future value is then used to do
something after the computation finishes.
Once the read operation is completed, the execution control is transferred
within "then()". This is because the reading operation can take more time and so it
doesn’t want to block other part of program.
Dart Future
The Dart community defines a Future as "a means for getting a value sometime in the
future." Simply put, Future objects are a mechanism to represent values returned by
Page | 77
an expression whose execution will complete at a later point in time. Several of Dart’s
built-in classes return a Future when an asynchronous method is called.
Dart is a single-threaded programming language. If any code blocks the thread of
execution (for example, by waiting for a time-consuming operation or blocking on I/O),
the program effectively freezes.
Asynchronous operations let your program run without getting blocked. Dart
uses Future objects to represent asynchronous operations.
Following on from my last post exploring the Dart language, I’d also been investigating
how one might go about building RESTful services with Dart. Some further digging and
I stumbled across Aqueduct by Stable Kernel. I was impressed at first glance seeing that
it has already passed version 2 and once I figured the documentation was
comprehensive with easy-to-follow examples, I was convinced to explore further.
Upon the experience of such a productive and refreshing time going through its
documentation and following their example, I am now pleased to be taking you on this
journey with me to build a working api from start to finish!
So what's Aqueduct?
Well it’s an open-source framework for creating and deploying RESTful web apis on the
server. It has a similar flavour to Express and Hapi, even .NET Web API, offering a
point of entry with a comprehensive list of features.
1. Fluid, chainable routing. A functional style to composing your routes and its
handler methods
2. A CLI tool. This allows you to scaffold your next project by issuing commands
3. Multi-threading out of the box. Spins up multiple instances of your application
via Dart's "isolates", scaling across all CPU cores on the server.
4. Has an inbuilt ORM. A must-have if you work with relational databases! Also
supports databse migration.
5. Has an integrated testing library. Because you need to test all the things! Plays
well with tools like TravisCI.
Page | 78
6. router.route('/').listen((request) async {
7. return new Response.ok('Hello world')
8. ..contentType = ContentType.TEXT;
9. });
In Part 1 we had a brief overview of Aqueduct, its features and learnt how to set up the
example project using its CLI tool.
In this part, we’ll be implementing a custom route with CRUD(create, read, update,
delete) capabilities.
Before jumping into this, we need to understand the concept of Routers and
HTTPControllers. This will inform the way we proceed. At the end of this part, we’ll
have our endpoint in place, with the ability to manipulate our data source through the
CRUD actions we define.
What is a Router?
Routers are responsible for capturing the request path and determining the logic that
runs based on it. The request path is defined by registering a route when calling
the route method on a Router object that is supplied to us. The registration occurs when
the setupRouter method in our FaveReadsSink subclass is called:
1. @override
2. void setupRouter(Router router) {
3. router.route('/router-1').listen(...);
4. router.route('/router-2').listen(...);
5. router.route('/router-3').listen(...); // and so on
6. }
Page | 79
Calling the route method accepts a string containing the path name, followed by
a listen method that then allows us to define the logic to run when a request is made to
this path. The route can contain path variables, which are placeholder tokens that
represent whatever value is in that segment of the path:
router.route('/items/:itemID');
1. @override
2. void setupRouter((Router router) async {
3. router.route('/books[/:index]').listen((Request incomingRequest) async {
4. return new Response.ok('Showing all books.');
5. });
6. router.route('/').listen((Request incomingRequest) async {
7. return new Response.ok('<h1>Welcome to FaveReads</h1>')
8. ..contentType = ContentType.HTML;
9. });
10. });
The root path(/) now returns HTML content. We also have a “/books” route defined
that accepts an optional path variable named index. This will be the endpoint for our
CRUD operations.
Invoking the route method returns a RouteController which exposes the listen method
for us to define our logic to run in. There are two other methods we can use,
namely pipe and generate. The latter allows us to create a new HTTPController object
that gives better handling of our request (more on that later).
The listen method accepts a closure containing a Request object that represents an
incoming request. We can then pull the information we need from that, perform
transformations, and return a response.
The current logic for “/books” return the same response regardless of the request
action. Let’s modify this to return a different response for each of our actions:
Page | 80
7. return new Response.ok('Showing book by index: $index');
8. }
9. return new Response.ok('Showing all books.');
10. } else if (reqMethod == 'POST') {
11. return new Response.ok('Added a book.');
12. } else if (reqMethod == 'PUT') {
13. return new Response.ok('Added a book.');
14. } else if (reqMethod == 'DELETE') {
15. return new Response.ok('Added a book.');
16. }
17. // If all else fails
18. return new Response(405, null, 'Not sure what you\'re asking here');
19. }); HTTPController
HTTPControllers
HTTPControllers respond to HTTP requests by mapping them to a particular ‘handler
method’ to generate a response. A request is sent to an HTTPController by a Router as
long as its path is matched.
1. import '../fave_reads.dart';
2.
3. class BooksController extends HTTPController {
4. // invoked for GET /books
5. @httpGet // HTTPMethod meta data
6. Future<Response> getAllBooks() async => new Response.ok('Showing all book
s');
7.
8. // invoked for GET /books/:index
9. @httpGet // HTTPMethod meta data
10. Future<Response> getBook(@HTTPPath("index") int idx) async => new Resp
onse.ok('Showing single book');
11.
12. // invoked for POST /books
13. @httpPost // HTTPMethod meta data
14. Future<Response> addBook() async => new Response.ok('Added a book');
15.
16. // invoked for PUT /books
17. @httpPut // HTTPMethod meta data
Page | 81
18. Future<Response> updateBook() async => new Response.ok('Updated a book')
;
19.
20. // invoked for DELETE /books
21. @httpDelete // HTTPMethod meta data
22. Future<Response> deleteBook() async => new Response.ok('Deleted a book');
23. }
4. A responder method can bind values from the request to its arguments. We see
this with the getBook() responder method argument: @HTTPPath("index") int
idx. It's path variable index is cast to an integer and assigned to a variable
named idx.
If none of the responder methods match the request method(e.g. PATCH), a 405
Method Not Allowed response is returned.
Let’s go to lib/fave_reads_sink.dart and use this controller:
1. import 'fave_reads.dart';
2. import 'controller/books_controller.dart'; // don't forget to import!
3. // ...
4. // ...
5. @override
6. void setupRouter((Router router) async {
7. router
8. .route('/books/[:index]')
9. .generate(() => new BooksController()); // replaces `listen` method
10. // ...
Page | 82
Mocking our datasource
For our datasource, let’s create an array
inside controller/books_controller.dart:
1. import '../fave_reads.dart';
2.
3. List books = [
4. {
5. 'title': 'Head First Design Patterns',
6. 'author': 'Eric Freeman',
7. 'year': 2004
8. },
9. {
10. 'title': 'Clean Code: A handbook of Agile Software Craftsmanship',
11. 'author': 'Robert C. Martin',
12. 'year': 2008
13. },
14. {
15. 'title': 'Code Complete: A Practical Handbook of Software Construction',
16. 'author': 'Steve McConnell',
17. 'year': 2004
18. },
19. ];
20.
21. class BooksController extends HTTPController {...}
We will then update our responder methods inside BooksController to manipulate this
dataset:
Page | 83
15. var book = request.body.asMap(); // `request` represents the current request. This is
a property inside HTTPController base class
16. books.add(book);
17. return new Response.ok(book);
18. }
19.
20. @httpPut
21. Future<Response> replaceSingle(@HTTPPath("index") int idx) async {
22. if (idx < 0 || idx > books.length - 1) { // index out of range
23. return new Response.notFound(body: 'Book does not exist');
24. }
25. var body = request.body.asMap();
26. for (var i = 0; i < books.length; i++) {
27. if (i == idx) {
28. books[i]["title"] = body["title"];
29. books[i]["author"] = body["author"];
30. books[i]["year"] = body["year"];
31. }
32. }
33. return new Response.ok(body);
34. }
35.
36. @httpDelete
37. Future<Response> delete(@HTTPPath("index") int idx) async {
38. if (idx < 0 || idx > books.length - 1) { // index out of range
39. return new Response.notFound(body: 'Book does not exist');
40. }
41. books.removeAt(idx);
42. return new Response.ok('Book successfully deleted.');
43. }
44. }
Restart the server again and test this out with Postman.
Please note: This is running in an isolate, which means that any side-effects can only be
seen in Postman’s(or whatever tool) session. Opening a separate session(like the
browser) will not show these changes. This is because isolates by design do not share
state. Not to worry though–this will be resolved when we implement the real database.
So remember when I said you could bind values from the request to the arguments of a
responder method? Well, we can refactor our POST operation to convert its payload to a
map through the @HTTPBody() metadata:
Page | 84
1. // lib/controller/book_controller.dart
2.
3. import '../fave_reads.dart';
4. import 'model/book.dart';
5.
6. List books = [
7. new Book(
8. title: "'Head First Design Patterns',"
9. author: 'Eric Freeman',
10. year: 2004
11. ),
12. new Book(
13. title: "'Clean Code: A handbook of Agile Software Craftsmanship', "
14. author: 'Robert C. Martin',
15. year: 2008
16. ),
17. new Book(
18. title: "'Code Complete: A Practical Handbook of Software Construction',"
19. author: 'Steve McConnell',
20. year: 2004
21. ),
22. ];
23.
24. class BooksController extends HTTPController {
25. // ...
26. // ...
27. Future<Response> addSingle(@HTTPbody() Book book) async { // note the `Book` ty
pe being used
28. books.add(book);
29. return new Response.ok(book);
30. }
31. //...
32. //...
33. }
Page | 85
Part 3: Connecting Web APIs to PostgreSQL database (we're
here)
Part 4: Writing automated tests
*Bonus content* DB Migration and Model Relationships 😄
In this part we'll replace the list with a PostgreSQL database, allowing us to persist the
information sent to our APIs. We will be using the inbuilt ORM to help with this.
I'd recommend installing Postgres.app on Mac as it's the easiest way to get going or use
the official download page for other options/platforms.
Once the server is running, use its command-line tool(psql) to create your database and
a user that can access it with the SQL commands below:
Create a ManagedContext
In order to tie our application to the database, it needs to:
The query object uses the where property which also is an instance of Book. This allows
us to add filtering to our data. The whereEqualTo function on the same line is one of the
matcher functions that come with Aqueduct. The above will execute the following SQL
query:
Page | 87
16. }
17. return new Response.ok(book);
18. }
19.
20. @httpPost
21. Future<Response> addBook(@HTTPBody() Book book) async {
22. var query = new Query<Book>()..values = book;
23. return new Response.ok(await query.insert());
24. }
25.
26. @httpPut
27. Future<Response> updateBook(@HTTPPath("index") int idx, @HTTPBody() Book bo
ok) async {
28. var query = new Query<Book>()
29. ..values = book
30. ..where.id = whereEqualTo(idx);
31. var updatedBook = await query.updateOne();
32.
33. if (updatedBook == null) {
34. return new Response.notFound(body: 'Book does not exist');
35. }
36. return new Response.ok(updatedBook);
37. }
38.
39. @httpDelete
40. Future<Response> deleteBook(@HTTPPath("index") int idx) async {
41. var query = new Query<Book>()..where.id = whereEqualTo(idx);
42. var deletedBookId = await query.delete();
43.
44. if (deletedBookId == 0) {
45. return new Response.notFound(body: 'Book does not exist');
46. }
47. return new Response.ok('Successfully deleted book.');
48. }
49. }
Page | 88
8. // Runs after all tests
9. tearDownAll(() async {
10. await app.stop();
11. });
The application is started before running all our tests and stopped immediately
afterwards. Our test harness replicates bin/main.dart with these exceptions:
1. A port 0 is specified so that our tests can run on any available port
2. A separate configuration file(config.src.yaml) is given containing test-specific data
3. The runOnMainIsolate option is set to true when application.start is called,
running our test on a main thread. This disables multi-threading so that we can
access the application's state and services to perform our assertions.
4. A TestClient is instantiated to provide a HTTP client for performing requests to
our APIs. Using this will give us test responses for making our assertions on.
5. A method for stopping the application is provided to be invoked after all tests are
run
In order to run our tests, let's refactor our solution in Part 3, starting with our database
configuration. This is to allow flexibility to support testing and production
environments.
1. // fave_reads_sink.dart
2. // ...
3. // ...
4. class FaveReadsSink extends RequestSink {
5. FaveReadsConfiguration config;
6.
7. FaveReadsSink(ApplicationConfiguration appConfig) : super(appConfig) {
8. logger.onRecord.listen(
9. (rec) => print("$rec ${rec.error ?? ""} ${rec.stackTrace ?? ""}"));
10.
11. var configFilePath = appConfig.configurationFilePath;
12. config = new FaveReadsConfiguration(configFilePath);
13.
Page | 89
14. var managedDataModel = new ManagedDataModel.fromCurrentMirrorSyste
m();
15. var persistentStore = new PostgreSQLPersistentStore.fromConnectionInfo(
16. config.database.username,
17. config.database.password,
18. config.database.host,
19. config.database.port,
20. config.database.databaseName);
21.
22. ManagedContext.defaultContext =
23. new ManagedContext(managedDataModel, persistentStore);
24. }
25. // ...
26. // ...
27. }
Page | 90
27. ..title = "Code Complete: A Practical Handbook of Software Construction"
28. ..author = "Steve McConnell"
29. ..year = 2004
30. ];
31.
32. await Future.forEach(books, (Book b) async {
33. var query = new Query<Book>()..values = b;
34. query.insert();
35. });
36. });
37.
38. tearDown(() async {
39. await app.discardPersistentData();
40. });
41.
42. //...tests to go here
43. }
The group function is used for categorising related tests, similar to having
the describe block if you've worked with the Jasmine BDD framework and test is similar
to the it block.
1. Our first test creates a request from our TestClient object, performs the GET
operation and runs our assertion on the response using
the expectResponse matcher method. It accepts the response, status code and
assertion under the body named parameter.
2. everyElement is another matcher method that allows us to run a check against
each item in the response body, assuming it's a list.
3. partial makes an assertion against specific keys, provided the list item is a Map.
We use this to save us checking every single key.
4. isString and isInteger are other inbuilt getters for ensuring the type is what we
expect
5. import 'harness/app.dart';
6. import 'package:fave_reads/model/book.dart';
7.
8. Future main() async {
9. TestApplication app = new TestApplication();
10.
11. setUpAll(() async {
12. await app.start();
13. });
14.
Page | 91
15. tearDownAll(() async {
16. await app.stop();
17. });
18.
19. setUp(() async {
20. // Populate DB
21. var books = [
22. new Book()
23. ..title = "Head First Design Patterns"
24. ..author = "Eric Freeman"
25. ..year = 2004,
26. new Book()
27. ..title = "Clean Code: A handbook of Agile Software Craftsmanship"
28. ..author = "Robert C. Martin"
29. ..year = 2008,
30. new Book()
31. ..title = "Code Complete: A Practical Handbook of Software Construction"
32. ..author = "Steve McConnell"
33. ..year = 2004
34. ];
35.
36. await Future.forEach(books, (Book b) async {
37. var query = new Query<Book>()..values = b;
38. query.insert();
39. });
40. });
41.
42. tearDown(() async {
43. await app.discardPersistentData();
44. });
45.
46. //...tests to go here
47. }
It works in this simple case, but what if we needed to specify multiple authors? Sure we
could and use commas as a separator, splitting them when we process each author, but
what if we wanted each author to have a short description? It certainly wouldn't be great
to store all that information in a single database column!
Ideally we want to capture this author property as its own entity so that we could
separate that concern as the application grows.
Let's create lib/model/author.dart with our Author model:
Page | 92
1. import '../fave_reads.dart';
2. import './book.dart';
3.
4. class Author extends ManagedObject<_Author> implements _Author {}
5.
6. class _Author {
7. @managedPrimaryKey
8. int id;
9.
10. String name;
11.
12. @ManagedRelationship(#authors) // <--
- Sets our column as a foreign key pointing to its associated book id
13. Book book;
14. }
Let's update our migrations directory by running aqueduct db generate. This will
generate another migration/*.migration.dart file alongside the earlier one. It builds
upon the initial migration file by adding SQL commands for:
Running the command below will upgrade the database to the updated schema:
Page | 93
9. ..year = 2004,
10. new Book()
11. ..title = "Clean Code: A handbook of Agile Software Craftsmanship"
12. ..authors =
13. (new ManagedSet()..add(new Author()..name = "Robert C. Martin"))
14. ..year = 2008,
15. new Book()
16. ..title = "Code Complete: A Practical Handbook of Software Construction"
17. ..authors =
18. (new ManagedSet()..add(new Author()..name = "Steve McConnell"))
19. ..year = 2004
20. ];
And in the loop afterwards, we create two queries to insert the books and the authors,
two because the model data goes into separate tables:
1. // ..
2. class BooksController extends HTTPController {
3. //..
4. @httpPost
5. Future<Response> addBook(@HTTPBody() Book book) async {
6. var query = new Query<Book>()..values = book;
7. var insertedBook = await query.insert();
8.
9. // Insert authors from payload
Page | 94
10. await Future.forEach(book.authors, (Author a) async {
11. var author = new Query<Author>()
12. ..values = a
13. ..values.book = insertedBook; // set foreign key to inserted book
14.
15. return (await author.insert());
16. });
17.
18. var insertedBookQuery = new Query<Book>()
19. ..where.id = whereEqualTo(insertedBook.id);
20.
21. insertedBookQuery.join(set: (book) => book.authors)
22. ..returningProperties((Author author) => [author.name]); // <-
- Specify the columns returned for each author in the response
23.
24. return new Response.ok(await insertedBookQuery.fetchOne());
25. }
26. //..
27. }
Check out the further reading materials below to understand database migration and
model relationships in further detail. As always, feedback is welcome. Let me know what
you liked, disliked and what you'd like to see next.
It seems that tech-giant Google has some big plans with the language. That’s why dart is
implemented on two big projects including flutter and fuchsia OS.
Here is a quick intro of dart’s features, use-cases and its humongous power Which will
give you answer why Google choose it for flutter and fuchsia OS.
Dart was first unveiled at the GOTO conference in Denmark on October 10, 2011. Dart
1.0 was released in November 2013 and Dart 2.0 was released in August 2018 with a
sound type system.
Page | 95
Dart is a very powerful language that you can use to write from simple scripts to full-
featured native apps using flutter. It is mainly used in four platforms including Native
Mobile App, Web App, Desktop App, and Server-Side App.
Dart is a member of the ALGOL language family, alongside C, C++, Java, C#,
JavaScript, and others.
So if you are from C, Swift, or Java’s background you’ll feel just like hometown in a dart.
Its syntax is closer to C.
1. C#
2. JavaScript
3. Erlang
4. Smalltalk
5. Strongtalk
It has four major implementations:
1. Dart VM
2. dart2js compiler
3. Flutter
4. Fuchsia OS
Page | 96
Dart is implemented on a wide range of platforms. So it needs multiple ways to run the
dart code depending on the platform. Below are three main ways to run the dart code:
Dart code can be compiled to JavaScript so that it can run on browsers. For that Dart
uses a source-to-source compiler (dart2js) to convert its code to JavaScript.
So when you want to deploy your Dart code on browsers, first you need to convert that
code via the dart2js compiler. dart2js will convert your code into JavaScript. So it can
run on all modern browsers.
Here amazing thing is, dart2js will not only produce JavaScript code, instead it will
produce optimized JavaScript code. That means compared to hand-written JavaScript
code, your converted dart code will run faster on browsers.
Through DartVM
Just like Java has JVM, Dart has its own virtual machine for running dart code-named
DartVM.
If you want to create console apps or server apps you can use DartVM to run Dart code.
DartVM is a highly optimized, powerful and fast virtual machine that can run your Dart
code in a fraction of seconds.
DartVM is directly coming with Dart SDK. You just need to setup SDK’s path in your
environment variables and you are ready to go. Your imagination is the only limit now…
Apps build with Flutter uses the same AOT compilation process to generate native
Android and iOS apps from a single code base.
Page | 97
SnapShots: For faster code execution
The same concept applies here, SnapShots are files which stores object and other
runtime data.
So in the next startup whole program does not need to be compiled, the compiler will
take saved data from snapshot files and compile only newly added data. Which results in
faster startups and code execution.
1. Script snapshots
2. Full snapshots
Script SnapShots
Dart programs can be compiled into SnapShots files. These files contain the program
code and dependencies pre-parsed and ready to execute. This allows fast start-ups.
Full SnapShots
The dart core libraries can be compiled into a snapshot file which allows fast loading of
the libraries.
Dart VM have a prebuild snapshot for the core libraries which is loaded at runtime.
That’s how DartVM provides faster code execution.
So, guys, these are the features and use-cases of a dart. It’s a very powerful language
itself. If you’re planning to go into app-development domain then you should definitely
start to learn dart and flutter. I’ll try to share as much as I can on dart and flutter. Feel
free to let me know if I missed something. I’ll definitely like to learn that.
Page | 98
In this three-part series, we will implement real-time functionality by building the
obligatory chat app. We will be working with various libraries that come with
the Dart SDK to achieve this and the Bulma CSS Framework for the UI styles.
At the end of this part, we will have the first UI view of our chat app fleshed out. Any
user that visits the app will have to enter their name in a sign in view before proceeding
to the chatroom.
1. Visitor enters their name and clicks the Join chat button. This sends the
username via POST request to our backend.
2. The backend receives and checks for the username, returning a 200 OK response
if valid, else a 400 Bad Request is returned.
3. On 200 OK the screen will be swapped to the Chatroom.
4. From here will be a WebSocket connection listening for messages sent from the
input field and broadcasted to other users on the chat.
5. Clicking the Leave chat button will close the WebSocket connection and return
to the username sign in screen.
We will use the UI style classes from Bulma to construct our screens.
In web/index.html, add the link tags below in the <head> before <link rel="stylesheet"
href="styles.css"> to import the latest minified styles and the Font Awesome icon font
dependency:
1. <section class="section">
2. <div class="container">
3.
4. <div id="ChatSignin">
5. <h1 class="title">Chatter 🎯</h1>
6. <div class="columns">
7. <div class="column is-6">
8. <div class="field">
9. <label class="label">Please enter your name</label>
10. <div class="control is-expanded has-icons-left">
11. <input class="input is-
medium" type="text" placeholder="Enter your name and hit ENTER" />
12. <span class="icon is-medium is-left">
13. <i class="fas fa-user"></i>
14. </span>
15. </div>
16. <p class="help is-danger"></p>
Page | 99
17. </div>
18. <div class="field">
19. <div class="control">
20. <button class="button is-medium is-primary">
21. Join chat
22. </button>
23. </div>
24. </div>
25. </div>
26. </div>
27. </div>
28.
29. <div id="ChatRoom" hidden>
30. <h1 class="title">Success!</h1>
31. </div>
32.
33. </div>
34. </section>
Let's add the logic to receive our username and send to the backend.
1. import 'dart:html';
2.
3. void main() {
4. // Selectors
5. var chatSigninBox = querySelector('#ChatSignin');
6. var chatRoomBox = querySelector('#ChatRoom');
7. var validationBox = chatSigninBox.querySelector('p.help');
8. InputElement nameField = chatSigninBox.querySelector('input[type="text"]');
9. ButtonElement submitBtn = chatSigninBox.querySelector('button');
10.
11. // Event listeners
12. nameField.addEventListener('input', (evt) {
13. // TODO: Run field validation
14. });
15.
16. submitBtn.addEventListener('click', (evt) async { // using async/await ;)
17. // TODO: Run name field validation
18. // TODO: Submit name field to backend
19. // TODO: Handle success response
20. // TODO: Handle failure responses
21. });
22. }
Page | 100
This will validate the field and add the appropriate classes for success and failure states.
These class names(is-success and is-danger) are provided by Bulma.
1. We check the username field for a valid entry. If not valid, we display an error
message and stop executing any further. If valid, then we move to step 2.
2. We send the form data to the endpoint at http://localhost:9780/signin
3. On successful response, we will hide the chat sign in UI and reveal the chatroom
UI
4. If the backend returns an error, we will replace the text of the Join chat button,
and encourage the user to try again
Page | 101
8. switch (request.uri.path) {
9. case '/signin':
10. String payload = await request.transform(Utf8Decoder()).join();
11. var username = Uri.splitQueryString(payload)['username'];
12.
13. if (username != null && username.isNotEmpty) {
14. // TODO: Check username is unique
15. request.response
16. ..write(username)
17. ..close();
18. } else {
19. request.response
20. ..statusCode = 400
21. ..write('Please provide a valid user name')
22. ..close();
23. }
24. break;
25. case '/ws':
26. // TODO: Upgrade request to Websocket connection
27. break;
28. default:
29. // TODO: Forward to static file server
30. }
At this point some of you may be wondering why we are using abstract class instead of
the interface keyword? Answer: The Dart team made it so! The rationale is that classes
are implicit interfaces so to simplify things they stuck with abstract classes.
1. // Absolute imports
2. import 'dart:html';
3.
4. // Relative imports
5. import './view.dart';
6.
7. class ChatSigninView implements View {
8. ChatSigninView() : _contents = DocumentFragment() {
9. onEnter();
10. }
11.
12. /// Properties
13. DocumentFragment _contents;
14. DivElement chatSigninBox;
15. ParagraphElement validationBox;
16. InputElement nameField;
Page | 102
17. ButtonElement submitBtn;
18. HttpRequest _response;
19.
20. @override
21. void onEnter() {
22. prepare();
23. render();
24. }
25.
26. @override
27. void onExit() {}
28.
29. @override
30. void prepare() {}
31.
32. @override
33. void render() {}
34. }
1. @override
2. void prepare() {
3. _contents.innerHtml = '''
4. <div id="ChatSignin">
5. <h1 class="title">Chatter 🎯</h1>
6. <div class="columns">
7. <div class="column is-6">
8. <div class="field">
9. <label class="label">Please enter your name</label>
10. <div class="control is-expanded has-icons-left">
11. <input class="input is-
medium" type="text" placeholder="Enter your name and hit ENTER" />
12. <span class="icon is-medium is-left">
13. <i class="fas fa-user"></i>
14. </span>
15. </div>
16. <p class="help is-danger"></p>
17. </div>
18. <div class="field">
19. <div class="control">
20. <button class="button is-medium is-primary">
21. Join chat
Page | 103
22. </button>
23. </div>
24. </div>
25. </div>
26. </div>
27. </div>
28. ''';
29.
30. chatSigninBox = _contents.querySelector('#ChatSignin');
31. validationBox = chatSigninBox.querySelector('p.help');
32. nameField = chatSigninBox.querySelector('input[type="text"]');
33. submitBtn = chatSigninBox.querySelector('button');
34.
35. _addEventListeners(); // TODO: Implement this method
36. }
Page | 104
34. try {
35. _response = await HttpRequest.postFormData(
36. 'http://localhost:9780/signin',
37. {
38. 'username': nameField.value,
39. },
40. );
41.
42. // Handle success response and switch view
43. onExit();
44. } catch (e) {
45. // Handle failure response
46. submitBtn
47. ..disabled = false
48. ..text = 'Failed to join chat. Try again?';
49. }
50. }
51. }
52.
53. chatSigninBox = _contents.querySelector('#ChatSignin');
54. validationBox = chatSigninBox.querySelector('p.help');
55. nameField = chatSigninBox.querySelector('input[type="text"]');
56. submitBtn = chatSigninBox.querySelector('button');
57.
58. _addEventListeners(); // TODO: Implement this method
59. }
Most of the logic above has been moved from web/main.dart from Part 1 of the series.
The _inputHandler() private method is responsible for validating the input text field
and adding the appropriate classes. The _clickHandler() private method will validate
and submit the form, POSTing to the endpoint at http://localhost:9780/signin.
1. // Absolute imports
2. import 'dart:html';
3.
4. // Relative imports
5. import './view.dart';
6.
7. class ChatRoomView implements View {
8. ChatRoomView(this.params)
9. : _contents = DocumentFragment() {
10. onEnter();
11. }
12.
Page | 105
13. /// Properties
14. Map params;
15. DocumentFragment _contents;
16. DivElement chatRoomBox;
17. DivElement chatRoomLog;
18. InputElement messageField;
19. ButtonElement sendBtn;
20.
21. @override
22. void onEnter() {
23. prepare();
24. render();
25. }
26.
27. @override
28. void onExit() {
29. _removeEventListeners(); // TODO: Implement this method
30.
31. // TODO: Transition to chat sign in screen
32. }
33.
34. @override
35. void prepare() {
36. _contents.innerHtml = '''
37. <div id="ChatRoom">
38. <h1 class="title">Chatroom</h1>
39. <div class="tile is-ancestor">
40. <div class="tile is-8 is-vertical is-parent">
41. <div class="tile is-child box">
42. <div id="ChatRoomLog"></div>
43. </div>
44. <div class="tile is-child">
45. <div class="field has-addons">
46. <div class="control is-expanded has-icons-left">
47. <input id="ChatRoomMessageInput" class="input is-
medium" type="text" placeholder="Enter message" />
48. <span class="icon is-medium is-left">
49. <i class="fas fa-keyboard"></i>
50. </span>
51. </div>
52. <div class="control">
53. <button id="ChatRoomSendBtn" class="button is-medium is-primary">
54. Send
55. <span class="icon is-medium">
56. <i class="fas fa-paper-plane"></i>
57. </span>
58. </button>
59. </div>
60. </div>
61. </div>
62. </div>
Page | 106
63. </div>
64. </div>
65. ''';
66.
67. chatRoomBox = _contents.querySelector('#ChatRoom');
68. chatRoomLog = chatRoomBox.querySelector('#ChatRoomLog');
69. messageField = chatRoomBox.querySelector('#ChatRoomMessageInput');
70. sendBtn = chatRoomBox.querySelector('#ChatRoomSendBtn');
71.
72. _addEventListeners(); // TODO: Implement this method next
73. }
74.
75. @override
76. void render() {
77. querySelector('#app')
78. ..innerHtml = ''
79. ..append(_contents);
80. }
81. }
82.
83. chatSigninBox = _contents.querySelector('#ChatSignin');
84. validationBox = chatSigninBox.querySelector('p.help');
85. nameField = chatSigninBox.querySelector('input[type="text"]');
86. submitBtn = chatSigninBox.querySelector('button');
87.
88. _addEventListeners(); // TODO: Implement this method
89. }
1. import './views/view.dart';
2.
3. // Type definition to label a Function that returns a `View` type
4. typedef ViewInstantiateFn = View Function(Map data);
5.
6. class Router {
7. Router() : _routes = [];
8.
9. List<Map<String, ViewInstantiateFn>> _routes;
10.
11. register(String path, ViewInstantiateFn viewInstance) {
12. // The key `path` is a computed property
13. // It could also be written as {'$path': viewInstance}
14. _routes.add({path: viewInstance});
15. }
16.
Page | 107
17. go(String path, {Map params = null}) {
18. // Find the matching `Map` object in _routes
19. // and invoke it's `View` object instance
20. _routes.firstWhere(
21. (Map<String, ViewInstantiateFn> route) => route.containsKey(path),
22. orElse: () => null,
23. )[path](params ?? {});
24. }
25. }
26.
27. Router router = Router();
The Router class contains a list of routes under the _routes instance variable. Each route
is a Map containing a key name which is the path and the value of that key is a function
that returns a View object. We've created a type definition called ViewInstantiateFn to
represent the structure of that function.
To add a route we will call the register() method, passing it a path and a function to
instantiate our View. To transition to the view we will call the go() method, passing it a
path and a map of parameters to be consumed by the View.
In order for messages to be relayed from one user and broadcasted to the others, we
need to establish a persistent, bi-directional connection to our server. This will allow
messages to be sent back and forth between the server and client using an event-based
architecture. This is made possible via the WebSocket protocol, which
the dart:io and dart:html library provides classes for. So no external packages
needed!
1. class ChatRoomSession {
2. final List<Chatter> _chatters = [];
3.
4. addChatter(HttpRequest request, String username) async {
5. // Upgrade request to `WebSocket` connection and add to `Chatter` object
6. WebSocket ws = await WebSocketTransformer.upgrade(request);
7. Chatter chatter = Chatter(
8. session: request.session,
9. socket: ws,
10. name: username,
11. );
Page | 108
12.
13. // Listen for incoming messages, handle errors and close events
14. chatter.socket.listen(
15. (data) => _handleMessage(chatter, data),
16. onError: (err) => print('Error with socket ${err.message}'),
17. onDone: () => _removeChatter(chatter),
18. );
19.
20. _chatters.add(chatter);
21.
22. print('[ADDED CHATTER]: ${chatter.name}');
23. }
24.
25. // TODO: Implement _handleMessage method
26. _handleMessage(Chatter chatter, String data) {}
27. }
We need a way of categorising the types of messages sent to our Chat server and respond
to it accordingly. When a participant joins the chat, it would be great to send a
notification welcoming this new participant and notifying the other participants on the
new chatter. We will create an enum type which will contain the particular types of
messages this Chat app will have.
Follow the full tutorial which includes tidying up the look and feel of the chat messages
and implementing the logout functionality.
References
1. https://github.com/imsanjoykb
2. https://github.com/smartherd
3. https://www.tutorialspoint.com/dart_programming/index.htm
5. dev.to
6. https://pub.dev/
Page | 109
Page | 110