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

Soundness in Dart

What is soundness?

Soundness ensures that the program never comes across any invalid state that may lead to abrupt termination of the program. As its name suggests it ensures perfect type matching that is the program can never get into the state where an expression evaluated to a value that doesn't match the static type of the expression.

For example if the static type of expression is String, we can only get a string value when we evaluate it at the runtime. Like in any other programming languages such as Java and C#, the Dart type system is also sound. It ensures the soundness using both static checking and runtime checking.

For example, if we asign 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.

Advantages of Soundness

There are various benefits of using sound type system: 

  • Revealing type-related bugs at compile time: A sound type system forces code to be unambiguous about its types, so type-related bugs that might be tricky to find at runtime are revealed at compile time.
  • More readable code: Code is easier to read because you can rely on a value actually having the specified type. In sound Dart, types can’t lie.
  • More maintainable code: With a sound type system, when you change one piece of code, the type system can warn you about the other pieces of code that just broke.
  • Better ahead of time (AOT) compilation: While AOT compilation is possible without types, the generated code is much less efficient.

Let's look at these rules in more detail, with examples using the following types of positions :

Animal sequence where the largest species is Animal and the subspecies are Snake, Cat, and Monkey. The cat has less breeds of Lion and Tiger

Use sound return types when overriding methods

The return type of a method in the subclass should be the same type or sub-type return method in the superclass. Consider how to find animals in the animal category :

class Animal {
  void chase( Animal a ) {  . . .  }
  Animal get parent => . . .
}

The parent getter( ) method returns ‘ Animal ’. In the ‘ Monkey ’ subclass, you can change the Getter recovery type with Monkey ( or any other sub-type of Animal ), but unrelated type is not allowed.

class Monkey extends Animal {
  @override
  void chase( Animal a ) { . . .  }
  @override
  Monkey get parent => . . .
}
class Monkey extends Animal {
  @override
  void chase( Animal a ) { . . . }
  @override
  Root get parent => . . .
}

Use sound parameter types when overriding methods

The output path parameter must have the same type or maximum corresponding parameter type in the superclass. " Do not override " the parameter type by substituting for the minimum version of the original parameter.

Note :

If you have good reason to use a subtype, you can use a covariant keyword.

Consider the ( Animal ) chase method of the Animal category:

class Animal {
  void chase( Animal a ) { . . . }
  Animal get parent => . . .
}

The chase( ) method takes an Animal. A ‘ Monkey ’ chases anything. It is okay to write down the chase( ) method of taking anything ( Object ).

class Monkey extends Animal {
  @override
  void chase( Object a ) { . . . }
  @override
  Animal get parent => . . .
}

The following code tightens the parameter on the chase( ) path from Animal to Mouse, a subclass ‘ Animal ’.

class Mouse extends Animal { . . . }
class Cat extends Animal {
  @override
  void chase( Mouse x ) { . . . }
}

This code is not a safe type because you will be able to identify the cat and send it after the Snake :

Animal a = Cat( ) ;
a.chase( Snake( ) ) ; // Not type safe or feline safe.

Do not use the dynamic list as a typed list.

A dynamic list is great if you want to have a list of different things in it. However, you cannot use dynamic lists as a typed list.

This rule also applies in cases of the general species.

The following code creates a dynamic list of Dogs, and gives it a list of Cat types, which creates an error during static analysis.

class Cat extends Animal { . . . }
class Dog extends Animal { . . . }
void main( ) {
  List< Cat > foo = < dynamic >[ Dog( ) ] ; // Error
  List< dynamic > bar = < dynamic >[ Dog( ), Cat( ) ] ; // OK
}

Runtime checks

Runtime checks in the Dart VM and dartdevc is dealing with security issues which the analyzer cannot handle.

For example, the following code does something different during operation because it is a mistake to publish a list of dogs in the cat list :

void main( ) {
List < Animals > animals = [ Dog ( ) ] ;
List < Cat > cats = animals as List < Cat > ;
}