Dart Tutorial

Dart Tutorial Single-Page Application Architecture Dart Features Dart Installation Guide Dart Basic Program Dart Syntax Dart Keywords Dart Variables Dart Comments Dart Standard Input Output Dart Important Concepts

Data Types

Built-in Data Types Numbers Strings Booleans Lists Sets Maps Runes and Graphemes Symbols Enumerations Constants Queues

Other data types

Objects Future and stream Iterable Miscellaneous types

OPERATORS

Precedence and associativity Arithmetic operators Equality and Relational operators Type Test Operators Assignment Operators Logical Operators Bitwise and Shift Operators Miscellaneous operators

Control Flow Statements

Introduction If statement If-else statement If-else-if statement Loops Switch and case Dart Break And Continue Assert In Dart

FUNCTIONS

Dart function Types of Functions Anonymous function main( ) function Lexical scope and closure Recursion Common Collection Methods

Object Oriented Concepts

Dart Object-Oriented Concepts Dart Classes Dart Constructors Dart This Keyword Dart Super Keyword Static Members Method Overriding Dart Interfaces Inheritance Dart Abstract Classes Dart Builder Classes Dart Callable Classes

Dart Type System

Dart Type System Dart Soundness Dart Type Inference

MISCELLANEOUS

Dart Isolates Dart Typedef Dart Metadata Dart Packages Dart Generics Dart Generators Dart Concurrency Dart Unit Testing Dart Html Dom Dart URIs Dart Extends, With and Implements Keywords Dart Optional Parameters Rust Vs Dart C++ vs Dart Golang Vs Dart Dart Basics Exception Handling

Type System in Dart

Dart language is a type safety enabled language that uses static and dynamic type checking to match the value of the variable with its data type at the compile-time. This is also known as sound typing. Although the types are mandatory, data type annotations are optional because of the type interference.

The static type checking is really advantageous as it has the ability to find the errors at the compile time using the static analyser of Dart. Most of the bugs interpreted by the static analyser can be fixed by declaring the generic classes along with the type annotations.

The most common generic classes are the collection types which are as follows :

  1. List< T >
  2. Map< K, V >.

For example, in the following code the int_list( ) function prints an integer list, and main( ) functions creates a list and passes it to the int_list( ) function.

Consider the following code in Dart that uses collection types :

Example – 1 :

void int_list( List< int > a) => print( a ) ;
void main( ) 
{
  var list = [ ] ;
  list.add( 5 ) ;
  list.add( ' Yukta ' ) ;
  int_list( list ) ;
}

Output :

The code did not compile as it resulted in a type error on the list when the function int_list( ) function is called.

Error :

Error compiling to JavaScript:
Info: Compiling with sound null safety
Warning: Interpreting this as package URI, 'package:dartpad_sample/main.dart'.
lib/main.dart:7:13:
Error: The argument type 'List<dynamic>' can't be assigned to the parameter type 'List<int>'.
 - 'List' is from 'dart:core'.
  int_list( list ) ;
            ^
Error: Compilation failed.

The error highlights an unsound implicit cast from List< dynamic > to List< int >. The list variable has static type List< dynamic >. The definition of the list as

var list = [   ] 

does not provide clear information to the type analyzer to interpret the type argument more specific than dynamic. The int_list( ) function expects a parameter of type List< int >, causing a mismatch of types.

Let us try to debug the above code.

We must begin with specifying a type annotation ( < int > ) while defining that list. It should be like :

var list = < int >[  ] ;

But still, the problem isn't solved completely.  The analyzer throws an error that the string type value can not be assigned to the integer type parameters as in the line :

list.add( ' Yukta ' ) ;

To solve this problem as well, we must add only the integer value like :

list.add( 2 ) ;

This will result in code passing static analysis and running with no errors or warnings.

void int_list( List< int > num ) => print( num ) ;
void main( ) 
{
  var list = < int >[  ] ;
  
  // adding the integer elements to the list
  list.add( 5 ) ;
  list.add( 10 ) ;
  list.add( 15 ) ;
  
  // printing the list
  int_list( list ) ;
}

Output :

[5, 10, 15]

What is soundness?

Soundness helps to ensure that the program successfully gets over the invalid states. A sound type system used in the program enables that the program never gets into a state where an expression is evaluated to a value that doesn't match the static type of the expression. For example, if an expression has a type ' String ' at the time of compilation, you are guaranteed only to get a string when you evaluate it at the run time.

Like in any other programming language such as Java and C#, the type system of Dart is sound. It enforces soundness using a combination of static checking ( compile - time errors ) and dynamic checking ( at runtime ). For example, assigning a String to int is a compile - time error. Casting an object to a String using as String fails with a runtime error if the object isn't a String.

The benefits of soundness

Sound type system has many benefits. Some of them are as follows :

  • Revealing type-related bugs at compile time : A sound type system ensures that the code is unambiguous with respect to the data types, such that the type - related bugs that might be difficult to find at runtime are successfully revealed at compile time.
  • More readable code: Code becomes more readable with the sound type safety because one can rely on a value actually having the exact specified data type. In sound Dart, types can’t lie.
  • More maintainable code : With a sound type system, whenever a piece of code is changed let us say the data type of a variable, the type system highlights and warns the programmer about the other places where the data type is still the old one.
  • Better ahead of time (AOT) compilation: While AOT compilation is possible without types; the generated code is much less efficient.

Tips for passing static analysis

Most of the rules for static types are easy to understand. Here are some of the less obvious rules:

  • Use sound return types when overriding methods.
  • Use sound parameter types when overriding methods.
  • Don’t use a dynamic list as a typed list.