Understanding The Dart Type System
Understanding The Dart Type System
The Dart language is statically typed language: it uses a combination of
static type checking and runtime checks to ensure that a variable’s value
always matches the variable’s static type, sometimes referred to as sound
typing.
what are types?
Types describe the type of data of object. Types are a useful feature because
they force you to write clean code and avoid mistakes/ bugs. For example, an
addition might only work with two numbers but not with two strings. With
types, you can ensure that a certain code expression only accepts numbers and
the compiler generates an undesired error if you pass wrong data.
Built-in types
The Dart language has following built-in types:
- numbers
- strings
- booleans
- lists (also known as arrays)
- sets
- maps
- runes (for expressing Unicode characters in a string)
- symbols
Note:
Every variable in Dart refers to an object which is an instance of a class. You can
usually use constructors to initialize variables. Some of the built-in types
have their own constructors. For example, you can use the Map() constructor to
create a map.
Numbers:
In dart Numbers are of two types
1. int
In Dart generally Integer values has size 8 bytes, depending on the platform.
On the Dart VM(Virtual Machine), values can be from -263 to 263
- 1. Dart that’s compiled to JavaScript uses JavaScript numbers, allowing
values from -253 to 253 - 1.
2. double
In Dart doubles are 64-bit (double-precision) floating-point numbers, as
specified by the IEEE 754 standard.
Integers are numbers without a decimal point. Here are some examples of
defining integer literals:
var x = 1; var hex = 0xDEADBEEF;
If a number includes a decimal, it is a double. Here are some examples of
defining double literals:
var y = 1.1; var exponents = 1.42e5;
As of Dart 2.1, integer literals are automatically converted to doubles when
necessary:
double z = 1; // Equivalent to double z = 1.0.
Version note:
Before Dart 2.1, it was an error to use an integer literal in a double
context.
Strings:
A Dart string is a sequence of UTF-16 code units. You can use either single or
double quotes to create a string:
var s1 = 'Hello '; var s2 = "world";
You can concatenate strings using adjacent string literals or the + operator:
var s1 = 'String ' 'concatenation' " works even over line breaks.";
assert(s1 =='String concatenation works even over ' 'line breaks.');
var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');
assert(s1 =='String concatenation works even over ' 'line breaks.');
var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');
Note:
assert( ) - During development, use an assert statement —
assert(condition, optionalMessage); — to disrupt normal execution if a boolean
condition is false.
Another way to create a multi-line string: use a triple quote with either
single or double quotation marks:
var s1 = '''You can create multi-line strings like this one.''';
var s2 = """This is also a multi-line string.""";
var s2 = """This is also a multi-line string.""";
You can create a “raw” string by prefixing it with r:
var s = r'In a raw string, not even \n gets special treatment.';
Note:
A rawstring is a string literal (prefixed with an r) in which
the normal escaping rules have been suspended so that everything is a literal.
Booleans:
To represent boolean values, Dart has a type named bool. Only two objects have
type bool: the boolean literals true and false, which are both compile-time
constants.
Dart’s type safety means that you can’t use code like
if(nonbooleanValue) or assert(nonbooleanValue). Instead,
explicitly check for values, like this:
// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);
// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);
// Check for null.
var unicorn;
assert(unicorn == null);
// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
var fullName = '';
assert(fullName.isEmpty);
// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);
// Check for null.
var unicorn;
assert(unicorn == null);
// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
Lists:
The most common collection in nearly every programming language is the array,
or ordered group of objects. In Dart, arrays are List objects, so most people
just call them lists.
Here’s a simple Dart list:
var list = [1, 2, 3];
Note:
Dart infers that list has type List<int>. If you try to add
non-integer objects to this list, the analyzer or runtime raises an error.
Lists use zero-based indexing, where 0 is the index of the first
element and list.length - 1 is the index of the last element.
You can get a list’s length and refer to list elements.
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
- To create a list that’s a compile-time constant, add const before the list literal:
var constantList = const [1, 2, 3];
Dart 2.3 introduced the spread operator (...) and the null-aware spread
operator (...?), which provide a concise way to insert multiple elements into
a collection.
For example, you can use the spread operator (...) to insert all the elements
of a list into another list:
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
var list2 = [0, ...list];
assert(list2.length == 4);
If the expression to the right of the spread operator might be null, you can
avoid exceptions by using a null-aware spread operator (...?):
var list;
list2 = [0, ...?list];
assert(list2.length == 1);
list2 = [0, ...?list];
assert(list2.length == 1);
Dart 2.3 also introduced collection if and collection for,
which you can use to build collections using conditionals (if) and
repetition (for).
Here’s an example of using collection if to create a list with three or four
items in it:
var nav = ['Home','Furniture','Plants',if (promoActive) 'Outlet'];
Here’s an example of using collection for to manipulate the items of a list
before adding them to another list:
var listOfInts = [1, 2, 3];
var listOfStrings = [ '#0', for (var i in listOfInts) '#$i'];
(listOfStrings[1] == '#1');
var listOfStrings = [ '#0', for (var i in listOfInts) '#$i'];
(listOfStrings[1] == '#1');
Sets:
A set in Dart is an unordered collection of unique items. Dart support for
sets is provided by set literals and the Set type.
Version note:
Although the Set type has always been a core part of Dart, set literals were
introduced in Dart 2.2.
Here is a simple Dart set, created using a set literal:
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Note:
Dart infers that halogens has the type Set<String>. If you try to
add the wrong type of value to the set, the analyzer or runtime raises an
error.
- To create an empty set, use {} preceded by a type argument, or assign {} to a variable of type Set:
var names = <String>{};
// Set <String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.
// Set <String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.
Set or map?
The syntax for map literals is similar to that for set literals. Because map
literals came first, { } defaults to the Map type. If you forget the type
annotation on { } or the variable it’s assigned to, then Dart creates an object
of type Map<dynamic, dynamic>.
- Add items to an existing set using the add() or addAll() methods:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
elements.add('fluorine');
elements.addAll(halogens);
- Use .length to get the number of items in the set:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);
- To create a set that’s a compile-time constant, add const before the set literal:
final constantSet = const
{'fluorine','chlorine','bromine','iodine','astatine',};
As of Dart 2.3, sets support spread operators (... and ...?) and collection
ifs and fors, just like lists do.
Maps:
In general, a map is an object that associates keys and values. Both keys and
values can be any type of object. Each key occurs only once, but you can use
the same value multiple times. Dart support for maps is provided by map
literals and the Map type.
Here are a couple of simple Dart maps, created using map literals:
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'};
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'};
var nobleGases = { 2: 'helium',
10: 'neon',
18: 'argon',};
10: 'neon',
18: 'argon',};
Note:
Dart infers that gifts has the type Map<String, String> and
nobleGases has the type Map<int, String>. If you try to add the
wrong type of value to either map, the analyzer or runtime raises an error.
- You can create the same objects using a Map constructor:
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
- Add a new key-value pair to an existing map:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair
gifts['fourth'] = 'calling birds'; // Add a key-value pair
- Retrieve a value from a map:
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');
assert(gifts['first'] == 'partridge');
If you look for a key that isn’t in a map, you get a null in return:
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
assert(gifts['fifth'] == null);
- Use .length to get the number of key-value pairs in the map:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
Runes and grapheme clusters:
In Dart, runes expose the Unicode code points of a string. As of Dart 2.6, use
the characters package to view or manipulate user-perceived characters, also
known as Unicode (extended) grapheme clusters.
Unicode defines a unique numeric value for each letter, digit, and symbol used
in all of the world’s writing systems. Because a Dart string is a sequence of
UTF-16 code units, expressing Unicode code points within a string requires
special syntax. The usual way to express a Unicode code point is \uXXXX, where
XXXX is a 4-digit hexadecimal value. For example, the heart character (♥) is
\u2665. To specify more or less than 4 hex digits, place the value in curly
brackets. For example, the laughing emoji (😆) is \u{1f606}.
If you need to read or write individual Unicode characters, use the characters
getter defined on String by the characters package. The returned Characters
object is the string as a sequence of grapheme clusters. Here’s an example of
using the characters API:
import 'package:characters/characters.dart';
...
var hi = 'Hi 🇩🇰';
print(hi);
print('The end of the string: ${hi.substring(hi.length - 1)}');
print('The last character: ${hi.characters.last}\n');
...
var hi = 'Hi 🇩🇰';
print(hi);
print('The end of the string: ${hi.substring(hi.length - 1)}');
print('The last character: ${hi.characters.last}\n');
The output, depending on your environment, looks something like this:
Hi 🇩🇰
The end of the string: ???
The last character: 🇩🇰
The end of the string: ???
The last character: 🇩🇰
Symbols:
A Symbol object represents an operator or identifier declared in a Dart
program. You might never need to use symbols, but they’re invaluable for APIs
that refer to identifiers by name, because minification changes
identifier names but not identifier symbols.
Minification:
In computer science, minification is the process of removing unnecessary
elements and rewriting code to reduce file size. It is commonly done to web
page resources, such as HTML, CSS, and JavaScript files.
To get the symbol for an identifier, use a symbol literal, which is just #
followed by the identifier:
#radix
#bar
Symbol literals are compile-time constants.
#bar
Symbol literals are compile-time constants.
It is interesting to know that Dart has a feature called
"type inference".
This means, if you created the variable with var, Dart is still able to infer
the type of that variable by the type of value you provided during the
initialization of the variable.
For example-
int num1;
num1 = 10;
var num2 = 10; // num2 is inferred as an int
num1 = 10;
var num2 = 10; // num2 is inferred as an int
Because of that built-in type inference, it's considered a good practice to
NOT explicitly define the type but instead use var when defining variables.
Very Informative
ReplyDeleteNice explanation
ReplyDeleteThankyou
Delete