Featured

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
Understanding The Dart Type System

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.');

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.""";

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);

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);

  • 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);
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);
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');


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 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);

  • Use .length to get the number of items in the set:

var elements = <String>{};
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'};

var nobleGases = { 2: 'helium',
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';

  • Add a new key-value pair to an existing map:

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair

  • Retrieve a value from a map:

var 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);

  • 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);

As of Dart 2.3, maps support spread operators (... and ...?) and collection if and for, just like lists do.

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');

The output, depending on your environment, looks something like this:

Hi 🇩🇰
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.


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
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.

Comments

Post a Comment