Operators

Last updated on September 13th, 2020

Basics

Unary, Binary, Ternary Operators

  • Unary – Operates on single operand

!true
  • Binary – Operates on a pair of operands

10 + 20
  • Ternary – Operates on 3 operands

count > 10 ? print("More") : print("Less")    // ?: is a single ternary operator

Prefix, Infix, Postfix Operators

  • Prefix – operator placed before the operand

-10
  • Infix – operator placed between the operands

10 + 20
  • Postfix – operator placed after the operand

employeeCount++

Note: The operator ++ has been deprecated in Swift. At present there are
no postfix operators in Swift by default. However you may define
custom postfix operators including ++ if needed.

Operator Precedence

It is the evaluation priority of  operators in an expression when mixed with operators of different  precedence groups. This is determined by the relative priority of the  precedence groups to which these operators belong.

2 + 3 * 4      // Result = 14 because it is evaluated as 2 + (3 * 4)
// + belongs to AdditionPrecedence group
// * belongs to MultiplicationPrecedence group
// AdditionPrecedence has lesser priority than MultiplicationPrecedence

Swift has many predefined precedence groups like AdditionPrecedence, MultiplicationPrecedence, ComparisonPrecedence etc.

Operator Associativity

It is the evaluation direction of  operators in an expression when mixed with other operators in the same  precedence group. This is determined by the associativity property of  the precedence group to which these operators belong.

5 % 3 * 2      // Result = 4 because it is evaluated as (5 % 3) * 2
// % and * belong to MultiplicationPrecedence group which has
// left associativity. Hence the expression is evaluated from
// left to right.

In Swift the associativity of a precedence group can be left, right or none.

Built-In Operators

Arithmetic Operators

+              // Addition
- // Subtraction
* // Multiplication
/ // Division

Bitwise Operators

These operate on the binary content of the value or variable

~              // Bitwise NOT                Eg: Result = ~InputVar
& // Bitwise AND Eg: Result = FirstVar & SecondVar
| // Bitwise OR Eg: Result = FirstVar | SecondVar
^ // Bitwise XOR Eg: Result = FirstVar ^ SecondVar
<< // Bitwise Left Shift Eg: Result = InputVar << 4
>> // Bitwise Right Shift Eg: Result = InputVar >> 5

Note:
* Left Shift and Right Shift of unsigned numbers discard the moved out bits and bring
in zeros at the other end. This is called logical shift.
* Left Shift of signed number works the same as that of unsigned number. Even the sign
bit is moved out and replaced by the shifted data bits. For example 10001000 becomes
00100000 after a left shift by 2 positions.
* Right Shift of signed number however retains the sign bit as such, in addition to
copying it to the most significant data bit with each shift. This is called an
arithmetic shift. For example 10001000 becomes 11110001 after a right shift by 3
positions.

Assignment Operator

Compound Assignment Operators

They combine assignment with another operation

+=             // Add and Assign                Eg: count += 1
-= // Subtract and Assign Eg: count -= 1
*= // Multiply and Assign Eg: count *= 2
/= // Divide and Assign Eg: count /= 2
%= // Remainder and Assign Eg: count %= 2
&= // Binary AND and Assign Eg: value &= 1
|= // Binary OR and Assign Eg: value |= 1
^= // Binary XOR and Assign Eg: value ^= 1
<<= // Left Shift and Assign Eg: value <<= 5
>>= // Right Shift and Assign Eg: value >>= 3

Overflow Operators

By default Swift throws error when the  inserted/updated value of a constant/variable is beyond the range of  values the respective type supports.

var sum: UInt8 = 0           // set sum to the minimum value supported by UInt8
sum = sum - 1 // throws error

var count: Int8 = 127 // set to the maximum value supported by Int8
count = count + 1 // throws error

However there are situations where the  developer would prefer an overflow instead of error. For this Swift  supports the following overflow operators.

&+                           // Overflow addition
&- // Overflow subtraction
&* // Overflow multiplication

Basically, these operators cause the value to wrap around (the other end of the range). In the above example,

sum = sum &- 1               // sum now becomes 255
count = count &+ 1 // count now becomes -128

Custom Operators

Operator Methods

An operator method is a static method,  defined inside a type definition/extension, with the operator symbol as  the method name, in order for the operator to accept values of that type  as operands. The body of the operator method should define the  appropriate behavior for the operation on the type. Operator methods are  used to support existing operators on a type that doesn’t support them  yet (operator overloading) as well as to define completely new  operators.

struct Score {
var physicsScore: Double = 0
var mathsScore: Double = 0

// Following is the operator method which defines overloaded behavior for +
// It is defined as a binary infix operator
static func + (left: Score, right: Score) -> Score {
return Score(physicsScore: left.physicsScore + right.physicsScore,
mathsScore: left.mathsScore + right.mathsScore)
}

// Following is the operator method which defines overloaded behavior for -
// It is defined as a unary prefix operator
static prefix func - (score: Score) -> Score {
return Score(physicsScore: -score.physicsScore, mathsScore: -score.mathsScore)
}
}

var firstSemScore = Score(physicsScore: 80, mathsScore: 85)
var secondSemScore = Score(physicsScore: 90, mathsScore: 95)

var totalScore = firstSemScore + secondSemScore // + is a binary infix operator
totalScore = -totalScore // - is a unary prefix operator

In order to overload a compound assignment operator, implement a binary infix method with the left parameter marked as inout.

struct Score {
var physicsScore: Double = 0
var mathsScore: Double = 0

// Overloaded method. Left parameter is inout and is assigned the result inside
// the method. Also note that the method need not return anything.
static func += (left: inout Score, right: Score) {
left = Score(physicsScore: left.physicsScore + right.physicsScore,
mathsScore: left.mathsScore + right.mathsScore)
}
}

var totalScore: Score = Score(physicsScore: 80, mathsScore: 85)
totalScore += Score(physicsScore: 90, mathsScore: 95)

Creating Custom Operators

Swift allows us to define custom  operators as well. This involves a global declaration of the new  operator and then defining the operator method within necessary structs,  classes etc.

The global declaration syntax is  different for different fixities (prefix, infix, postfix). Prefix and  Postfix operators are non-associative and do not belong to any  precedence group.

prefix­ operator­ OperatorSymbol
Eg: prefix operator +++

postfix operator OperatorSymbol
Eg: postfix operator +++

infix operator OperatorSymbol: PrecedenceGroup
Eg: infix operator +++ : AdditionPrecedence

Example

infix operator +++ : AdditionPrecedence

struct Score {
var physicsScore: Double = 0
var mathsScore: Double = 0

static func +++ (left: Score, right: Score) -> Score {
return Score(physicsScore: left.physicsScore + right.physicsScore + 100,
mathsScore: left.mathsScore + right.mathsScore + 100)
}
}

var firstSemScore = Score(physicsScore: 80, mathsScore: 85)
var secondSemScore = Score(physicsScore: 90, mathsScore: 95)

var totalScore = firstSemScore +++ secondSemScore

Note: Please refer to Apple documentation for the set of symbols that you can use to define a new operator.

Creating Custom Precedence Groups

A precedence group is declared as follows

precedencegroup precedenceGroupName {
higherThan : lower group names // Specify relation to any lower groups
lowerThan : higher group names // Specify relation to any higher groups
associativity : associativity // Specify the associativity (left, right, none)
assignment : assignment flag // Specify precedence while optional chaining
}

Note: The assignment flag decides the precedence of the operators of this group when used in an expression with optional chaining. When it is set to true, these operators follow the same grouping rules as the assignment operator. When set to false, they follow the optional chaining rules as those operators which do not perform assignment.

Example

precedencegroup myOperatorsPrecedence {
higherThan : AdditionPrecedence, ComparisonPrecedence
lowerThan : MultiplicationPrecedence
associativity : left
assignment : false
}

Leave a Reply

Your email address will not be published. Required fields are marked *