Dart Apprentice Fundamentals
Dart Apprentice Fundamentals
John Adel
August 2, 2024
Dart:
Operators in Dart:
add: +
subtract: -
multiply: *
divide: /
assignment operator: =
equality operator: ==
dot operator: .
OR operator: ||
1
2 Expressions, variables & constants
1. you can make a single-line comment by typing //
if you want to know what is a documentation comment read the next paragraph:
have you ever used an IDE and when you tried to use a method it showed you what does it
do, what is its return value and what are/is its parameters. If you have seen that, Congratu-
lations you have seen a documentation comment which you can make yourself by typing the
documentation comment before the class, method or function by using the /// for single-line
documentation comment or by using /** and */ for block documentation comment.
Application Programming Interface (API): is code that you share with other people or
programs.
Note: In Dart, all simple statements end with a semicolon while the complex statements and
code blocks that use curly braces don’t end with a semicolon.
Truncating division operator (∼/): it is an operator that ignores the decimal part provid-
ing an integer as your answer.
Operator Precedence: refers to the order in which operation are evaluated in an expression
(Google assistant: Gemini)
Type annotation: are specifications that provide information about the data type of a vari-
able, function parameter, or return value and others. (Google assistant: Gemini)
Type-Safe Language: it means once you determine the variable’s type, you can’t change it
later.
dynamic data type: it lets you assign any data type you like to your variable.
2
Mutable Data: they are variables whose value can be changed.
Compile-Time Constants: values that can be determined by the compiler before the pro-
gram ever starts running. (we use const with this one)
Runtime Constant: values that can be determined at runtime which means after the pro-
gram starts running. (we use final with this one)
3
3 Types & Operations
Note: programming types help you to categorize all the different kinds of data you use in your
code.
Type: is a way to tell the compiler how you plan to use some data.
Note: types like int, double and num are subclasses, or subtypes, of the Object type.
Note: Object defines a few core operations, such as testing for equality and describing itself.
Every non-nullable type in Dart is a subtype of Object, and as a subtype, shares Object’s basic
functionality.
Note: you must explicitly write the type annotation when you initialize a variable but you can
optionally write the type annotation when it is const or final as the compiler can figure the
type out in this case.
Type Inference: it is a process in which the compiler can figure the type out on its own.
Statically-typed: it means that the type can not be changed once it is written because the
type is determined at compile-time.
Optionally-typed: it means that you can choose the programming language to be dynami-
cally or statically typed. And in this case it’s dart.
Note: Object? and dynamic behave nearly the same. However, when you explicitly declare a
variable as Object?, you’re telling everyone that you generalized your variable on purpose and
that they’ll need to check its type at runtime if they want to do anything specific with it. using
dynamic, on the other hand, is more like saying you don’t know what the type is; you’re telling
people they can do what they like with this variable, but it’s completely on them if their code
crashes.Also, the ? after the Object? means that the type can include null.
4
4 Strings
Note: computers think of strings as a collection of individual characters.
Note: a computer needs to be able to translate a character into the computer’s own language,
and it does so by assigning each character a different number.
Character Set: it is a two-way mapping between characters and numbers in which each char-
acter is assigned to a number.
Unicode: defines the character set mapping that almost all computers use today.
.codeUnits : gives the code points and if the code point is bigger than 65,536 it will return
the surrogate pair.
Surrogate Pairs: a special way that UTF-16 uses to encode code points higher than 65,536.
Regional Indicator Symbols: it is a pair of code points that is used to represent a flag.
Zero Width Joiner (ZWJ): it is how the family is glued up together in the family emoji.
user-perceived character: its when a string with multiple code points looks like a single
character.
Interpolation: is a special dart syntax that lets you build a string in a manner that’s easy for
other people reading your code to understand.
raw string: it is used when you want to ignore special characters by putting r in front of the
string literal.
\u : it is followed by a four-digit hexadecimal code unit value to print what you want.
5
5 Control Flow
control flow: refers to the order in which individual statements, instructions, or function calls
are executed or evaluated in a programming language. It is typically managed using structures
like loops, conditionals, and function calls. (ChatGPT)
Scope: is the extent to which a variable can be seen throughout your code.
local variable: is a variable that is declared within a function or a block and can only be
accessed and used within that function or block. (ChatGPT)
enumerated data type: are a special kind of data type that allows you to define a set of
named values, which represent all possible values that a variable of that type can have.
(ChatGPT)
6
6 Loops
infinite loop: is a loop that never stops.
7
7 Functions
function: is one small task, or sometimes a collection of several related tasks, that you can
use in conjunction with other functions to accomplish a larger tasks.
DRY: don’t repeat yourself, which means if you have a piece of code that is written multiple
times in different places in your program, use a function.
function signature: in Dart, it is the return type, function name and parameters.
parameter: in Dart, it is the name and type that you define as an input for your function.
argument: the value you provide inside the parentheses as the parameter to the function.
positional parameters: are parameters that are specified by their position in the function
call. They can be required or optional, with optional positional parameters enclosed in square
brackets []. (ChatGPT)
Note: you can use optional parameters by surrounding the parameter with square brackets
and giving it a default value.
named parameters: are parameters that are specified by name in the function call. They are
enclosed in curly braces and can be made required or optional. Named parameters improve
code readability by clearly indicating the role of each argument. (ChatGPT)
required Keyword: it is used when you want to make the parameter a named parameter but
because named parameters are by default optional, you can use the required keyword to make
it essential.
side effect: anything that affects the world outside the function.
Single Responsibility Principle: states that a class or function should have only one reason
to change, meaning it should have only one job or responsibility. This principle helps make
code more modular, easier to understand, and maintainable by ensuring each class or function
focuses on a single task. (ChatGPT)
Note: you can omit the types from your function declaration since Dart is an optionally-typed
language.
arrow syntax (arrow notation): if the function is one line, you can use this syntax to write
the function by omitting the braces and the return keyword and replace them with an arrow.
8
8 Classes
class: is like architectural blueprints that tell the system how to make an object.
constructor: is a special method you use to create object from the class.
Serialization: is the process of converting a complex data object into a form you can store or
transmit, usually a string.
Deserialization: which is simply the process of converting a string back into an object of your
data type.
Encapsulation: this the principle of hiding the internal data and logic in aclass from the
outside world. Doing so has a few benefits:
The class controls its dat, including who sees it and how it’s modified.
Encapsulation prevents unrelated classes from reaching and modifying data, which can
cause hard-to-find bugs.
You can change the internal variable names and logic without breaking things in the
outside world.
private: in Dart, private means library private, not class private. A Dart library generally
corresponds to a single file. That means other classes and functions in the same file have access
to variable names that begin with an underscore. But these same variables are invisible from
other libraries.
getter method: is a special method that returns the value of a private filed variable. it’s the
public face of a private variable.
get keyword: it provides a public-facing property name. This means that from the perspective
of someone using your class, it looks like they are accessing a simple property, but under the
hood, there might be more complex logic determining the value that is returned. (ChatGPT)
Note: Multiplying a string by a number repeats the string that many times.
9
Note: Dart implicitly generates the needed getters and setters for you.
Note: variables in a class fields, and public fields or getter methods are called properties.
10
9 Constructors
Constructors: are methods that create, or construct, instances of a class.
generative constructor: refers to a typical constructor that you define to initialize objects
of your class. (ChatGPT)
this keyword: allows you to disambiguate which variable you’re talking about. It means this
object.
shadowing: using the same name for the constructor parameters as the class properties.
Note: if you use the initializer list, the constructor would initialize the properties before the
body.
canonical instances: it means no matter how many instances you create, as long as the
properties used to create them are the same, Dart will only see a single instance.
factory constructors: provides more flexibility in how you create your object. A generative
constructor can only create a new instance of the class itself. However, factory constructors
can return existing instances of the class, or even subclasses of it. It starts with the factory
keyword and returns an object of the class type.
11
10 Static Members
static: putting static in fromt of a member variable or method causes the variable or method
to belong to the class rather than the instance.
class variables: they are static variables that belong to the class.
singleton class: are a common design pattern with only one instance of an object.
lazily initialized: static fields and top-level variables - global variables outside of a class are
to lazily initialized which means Dart doesn’t calculate and assign their values until you use
them first.
Note: the static keyword goes at the beginning of the method signature.
12
11 Nullability
sound null safety: taking null out of the list and only put it back if you allow Dart to do so.
Note: null actually is a value in the sense that it’s an object. that is, the object null is the
sole instance of the Null class.
Note: nullable types end with a question mark(?) while non-nullable types do not.
Note: a nullable type can contain the null value in addition to its own data type and you can
determine the nullable type by as it ends with a question mark (?).
Note: the question mark at the end of String? isn’t an operator acting on the String type.
Rather, String? is a whole new type separate from String. String? means that the variable can
either contain a string or it can be null. It’s a union o f the String and Null types.
Note: the non-nullable type is a subtype of its nullable form. For example, String is a subtype
of String? since String? can be a String.
Note: for any nullable variable in Dart, if you don’t initialize it with a value, it’ll be given the
default value of null.
Dart analyzer: is the tool that tells you what the compile-time errors and warnings are.
type promotion: dart promotes the nullable and largely unusable String? type to a non-
nullable String with no extra work from you!
Note: Dart uses sophisticated flow analysis to check every possible rout the code could take.
As long as none of the routes come up with the possibility of null.
null-aware operators: are tools that can help you handle potentially null values.
null-aware operators:
?? : if-null operator.
this operator says: ”If the value on the left is null, then use the value on the right.”
13
?.. : null-aware cascade operator.
this operator works exactly like the cascade operator.
Note: Dart doesn’t let you access instance methods during initialization.
lazy initialization: using late means that dart doesn’t initialize the variable right away. It
only initializes it when you access it the first time.
Note: Dart doesn’t complain at you, because using late means that you’re promising Dart
that you’ll initialize the field before it’s ever used. This moves checking from compile-time to
runtime.
14
12 Lists
Note: list is the primary collection type you’ll work with in Dart.
Note: a list is ideal for storing many objects of the same type in a n ordered way. Lists in
dart are like what other languages call arrays.
angle brackets ¡¿: in lists, are the notation for generic types.
generic list: means you can have a list of anything; you just put the type you want inside the
angle brackets.
subscript notation: is a way to access a list’s elements where the index number goes in a
square brackets after the list name.
Note: with final list. Even though the memory address is constant, the values at that address
are mutable.
deeply immutable: meaning every element of the list must also be a compile-time constant.
Note: modifying an unmodifiable list will cause a runtime error - not a compile-time error.
Note: a few possibilities exist when dealing with null values and lists. Either the list itself
could be null, or the values within the list could be null.
15
13 Sets
set: is a collection of elements where the order isn’t important and duplicate elements are
ignored.
Note: this makes them ideal for quickly checking whether an element exists in a collection.
If you wanted to know whether a list of desserts contained donuts, you’d have to check each
dessert to find out. Not so with sets. You ask a set if there are donuts, and the set tells you
immediately: yes, there’s or there’s not.
constant time complexity: that means no matter how many elements the set contains, it
will take the same amount of time to tell you whether a particular value exists in the set or
not. There are minor exceptions to that rule, but it’s true in the average case.
linear time complexity: that means that the method has to look at each element in a list
to check if the value is the same.
Note:
shallow copy: that means the elements in the copy still point to the same objects in memory
as the elements in the original collection; the elements aren’t recreated as new objects with the
same values. If those elements are mutable, changing them will modify their values in both
copies of the collection.
Deep copy: it is where even the elements are copied to new objects, and in that case you have
to implement that behavior yourself.
Note: Set.toSet also works with List.toList when you copy a list.
Note: if you have a list and you want to find the unique values without the duplicates you
could just turn it into a set by using .toSet()
seed: a number used to initialize the internal algorithm that produces the pseudo-random
values.
16
14 Maps
Maps: in Dart, they are the data structure used to hold key-value pairs.
Note: when you don’t specify a generic type for example like this:
it turns out map literals came before se literals in Dart’s history, so Dart infers the empty
braces to be a Map of ¡dynamic, dynamic¿. In other words, the types of the key and value are
both dynamic. If you want a set rather than a map, then you must be explicit.
Note: keys must be unique while values don’t have that same restriction of being unique.
Note: a map will return null if the key doesn’t exist. Because of this, accessing an element
from a map always gives a nullable value.
Note: if you assign a value to a key that already exists, you overwrite the existing value and
that is because the keys of a map are unique as mentioned before.
Note: adding to, updating and removing key-value pairs from a map are fast operations.
Checking fro a key with conatainsKey is fast, but checking for a value with containsValue is
potentially slow because Dart has to iterate through possibly the entire collection of values.
Note: JSON itself is a string rather than a map, so technically, you should probably call this
method toMap. But common practice is to call it toJson.
17
15 Iterables
iterable: it is any collection that lets you loop through its elements. In more technical speak,
it’s a class that implements the Iterable interface.
Note: the parentheses are Dart’s way of telling you this is an Iterable and not a list.
synchronous generator: it is a type of a generator where the values come in the form of an
iterable and it was named like that because the values are available on demand when you need
them.
asynchronous generator: it is another type of generator where you have to wait for the
values to become available.
sync∗ : read that as ”sync star”. which means that you are telling dart that this function is a
synchronous generator which in this case must return an Iterable from such a function.
yield: this is similar to the return keyword for normal functions except that yield doesn’t exit
the function. Instead, yield generates a single value and then pauses until the next time you
request a value from the iterable. Because iterables are lazy, Dart doesn’t start the generator
function until the first time you request a value from the iterable.
bool moveNext(): in this method, you provide the logic for how to get the next element in
the collection. The method needs to return a Boolean value. As long as more elements remain
in the collection, it returns true. A value of false means the iterator has reached the end of the
collection.
current: this is a getter that returns the value of the element in your current progress of
iteration through the collection. current is considered undefined until you call moveNext at
least once. It’s also undefined after the iterator reaches the end of the collection, the is after
moveNext has returned false. Depending on the implementation, trying to access an undefined
current might return a reasonable value or it might cause a crash. The behavior is undefined,
though, so don’t try. That’s the agreement you make when you use an iterator.
18