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

Dart Operators Precedence and Associativity

Precedence of operators determines the order in which the operators are evaluated if they are grouped together in a sentence. If two operators share an operand then the one with the higher precedence is executed first.

Program

Consider the following code in Dart that uses two Arithmetic Operators viz multiply (*) and add (+), and an assignment operator viz. equals to (=).

void main( )
{
    int a = 5, b = 6, c = 7, res1 = 0, res2 = 0 ;
  
    res1 = a + b * c ;
  
    // result of first expression
    print( res1 ) ;
  
    res2 = a * b + c ;
    
    // result of second expression
    print( res2 ) ;
}

Output:

47
37

Let us understand how the answers to these two results differ. In the first expression res1 = a + b * c with a = 5, b = 6, and c = 7.

Multiplication is performed first because it has higher precedence than the addition operator.

Therefore, the answer evaluated to 47.

res1 = a + b * c = 5 + 6 * 7

                                 = 5 + 42

                              = 47

Similarly in case of second expression,

Multiplication is performed first followed by addition

res2 = a * b + c = 5 * 6 + 7

                                = 30 + 7

                                = 37

Since the assignment operator has the least precedence out of these three, it is used at the last after we have evaluated the expression at the right. And then using assignment operator the value evaluated is assigned to the variable on the left.

Sometimes, the operators with same precedence are used in an expression together. In that case we need a rule that defines the order in which they should be performed and that is given by Associativity of the operators. It determines the direction in which an expression is evaluated. It can be either Left to Right or Right to Left.

Program

Consider the following code in Dart that uses Multiplicative operators  : multiply (*) and divide (/), Additive Operators : add (+) and subtract (-) and assignment operator : equals to (=)

void main( )
{
    int a = 12, b = 6, c = 16, d = 8;
    var res1, res2, res3, res4;
  
    res1 = a - b + c * d;
  
    // result of first expression
    print( res1 ) ;
  
    res2 = a / b * c + d ;
    
    // result of second expression
    print( res2 ) ;
  
    res3 = a * b / c - d ;
  
    // result of third expression
    print( res3 ) ;
  
    res4 = a + b - c / d ;
  
    // result of fourth expression
    print( res4 ) ;
}

Output:

134
40
-3.5
16

PRECEDENCE AND ASSOCIATIVITY TABLE

Let’s have a look at the table that defines the precedence and associativity of each operator in Dart.

LEVELCATEGORYOPERATORASSOCIATIVITY
16Unary Postfixexpr.
expr ?.
expr ++
expr --
expr1
[ expr2 ]
expr( )
 
15Unary Prefix- expr
! expr
++ expr
-- expr
~ expr
await expr
 
14Multiplicative*
/
~
/
%
Left – to - right
13Additive+
-
Left - to - right
12Shift< <
> >
> > > >
Left – to - right
11Bitwise AND&Left - to - right
10Bitwise XOR^Left – to - right
9Bitwise OR Postrix|Left – to - right
8Relation and Test type

< =
> =
as
is
is! 
 
7Equality= =
= !
 
6Logical AND&&Left – to - right
5Logical OR| |Left - to - right
4If nullexpr1 ?? expr2Left – to - right
3Conditionalexpr ? expr1 : expr2Right - to - left
2Cascade. .Left – to - right
1Assignment=
* =
/ =
+ =
- =
& =
^ =
< * lt ; =
>> =
?? =
~ / =.
| =
% =
Right - to - left

Overriding Precedence

We are clear by now that the operators are executed in an expression as per their precedence. But what if we want them to be executed exactly in the sequence they are written in an expression?

For example

In an expression that contains multiplication operator (*) and addition operator (+), we know that multiplication will be done first. But in order to perform addition first, we can use round parenthesis with the operator and operands.

Consider the following code in Dart that explains the above point

void main( )
{
    int a = 5, b = 6, c = 7;
    var res1, res2, res3, res4 ;
  
    res1 = a + b * c ;
    
    // printing the result of first expression
    print( res1 ) ;
  
    res2 = a * b + c ; 
  
    // printing the result of second expression
    print( res2 ) ;
  
    res3 = ( a + b ) * c ;
  
    // printing the result of third expression
    print( res3 ) ;
  
    res4 = ( a * b ) + c ;
  
    // printing the result of fourth expression
    print( res4 ) ;
} 

Output:

47
37
77
37

Precedence Class

A particular row in the Dart expression precedence table is represented by an instance of the expression class. This allows programmers to determine when parentheses are required (by comparing precedence values), but ensures that the programmer does not depend on the particular integers used by the analyser to represent table rows, since it may be required to change these integers from time to time to accommodate new language features.

Constructors

  1. Precedence.forTokenType constructor = This constructor is used to construct the precedence of the unary or binary expression containing operators of a particular given ‘type’.

Implementation = Precedence.forTokenType ( TokenType type ) : this._( type.precedence ) ;

Properties

1. HashCode =

Returns the hash code for a numerical value, and it returns the same value for int and doubles when the value provided is the same. 

Implementation =

@override

int get hashCode = > _index.hashCode ;

2. Runtime Type =

Represents the type of runtime an object has. 

Implementation = external Type get runtimeType ;

Operators

1. Operator <

It checks whether the precedence represents a looser binding than other, and accordingly returns true or false.

Implementation = bool operator < ( Precedence other ) = > _index < other._index ;

2. Operator < =

It checks whether the precedence represents a looser, or equal binding than other, and accordingly returns true or false.

Implementation = bool operator < = ( Precedence other ) = > _index < = other._index ;

3. Operator = =

It returns true if and only if this object and the other are the same.

Implementation =

@override

bool operator = = ( Object other ) = >

    other is Precedence && _index = = other._index ;

4. Operator >

It checks whether the precedence represents a tighter binding than other, and accordingly returns true or false.

Implementation = bool operator > ( Precedence other ) = > _index > other._index ;

5. Operator > =

It checks whether the precedence represents a tighter, or equal binding than other, and accordingly returns true or false.

Implementation = bool operator > = ( Precedence other ) = > _index > = other._index ;