Compiled Chronicles

A software development blog by Angelo Villegas

Swift: Operator Declaration

The Swift standard library defines a number of operators, many of which are available to most programming languages. The most familiar operators that will come to mind are the MDAS operators’ */+- respectively.

Operators such as these are very simple to use and remember that it was thought ever since we were kids. But not all operators are easy to remember, not all of them are easy to use, and not all of them are used in a day-to-day life of an average person.

Many programming languages uses functions instead for non-standard operators such as the square root operator . Programming languages uses sqrt() instead as the standard function name, as it is easier to remember than typing ALT + 251 for Windows or CTRL + SHIFT + u221a for Ubuntu.

However, with a Mac, typing a square root symbol is much easier than typing the function name, that means it will take longer for us to type in the function sqrt() than calling the square root symbol using our keyboard by only typing Option + V. This is where operator declaration comes in.

Operator Declaration

An operator declaration introduces new line of operators with modifiers called fixitiesinfixprefix, and postfix modifiers are declared right before the keyword operator.fixity operator operator-name { precedence precedence-level associativity associativity }

Declaring custom operators are very useful, if you need a custom calculation that can be shortened to a combination of operators, operator declaration may help.

Fixity

The fixity of an operator specifies the relative position of an operator to its operands.

Prefix Operator

A prefix operator is a unary operator that is written immediately before its operand, such as the prefix increment operator ++ is in the expression ++i.

Prefix operator declaration don’t specify a precedence level and they are non-associative.

The following form declares a new prefix operator:prefix operator operator-name {}

Infix Operator

An infix operator is a binary operator that is written between its two operands, such as the familiar addition operator + in the expression 1 + 2.

Infix operators can optionally specify a precedence, associativity, or both.

Infix operator declaration that are declared without specifying a precedence or associativity are initialised with a precedence level of 100 and an associativity of none.

The following form declares a new infix operator:infix operator operator-name {}

Postfix Operator

A postfix operator is a unary operator that is written immediately after its operand, such as the postfix increment operator ++ is in the expression i++.

As with prefix operators, postfix operator declaration don’t specify a precedence level and are non-associative.

The following form declares a new postfix operator:postfix operator operator-name {}

Precedence Level

You specify the precedence of an operator by writing the keyword precedence followed by the precedence level. The precedence level can be any whole number from 0 to 255.

The precedence of an operator specifies how tightly an operator binds to its operands in the absence of grouping parentheses.

Unlike decimal integer literals in Swift, precedence level can’t contain any underscore characters.

That is, when two operators compete with each other for their operands, such as in the expression 2 + 3 * 5, the operator with the higher precedence level binds more tightly to its operands.

In the case above, the multiplication operator * has a higher precedence level than the addition operator + and tells the compiler that 3 * 5 should be calculated first before 2 + 3; the formula 2 + 3 * 5 will evaluate to 17 instead of 25

Associativity

You specify the associativity of an operator by writing the keyword associativity followed by the associativity, which is one of the keywords leftright, or none.

The associativity of an operator specifies how a sequence of operators with the same precedence level are grouped together in the absence of grouping parentheses. Operators that are left-associative group left-to-right. The subtraction operator - is an example of a left-associative operator, and therefore the expression 4 - 5 - 6 is grouped as (4 - 5) - 6 and evaluates to -7.

Non-associative operators of the same precedence level can’t appear adjacent to each other.

Operators that are right-associative group right-to-left, and operators that are specified with an associativity of none don’t associate at all.

After declaring a new operator, you implement it by declaring a function that has the same symbol as the operator.

Custom Operators

Custom operators can start with the characters / = - + * % < > ! & | ^ . ~, or Unicode math symbols, arrow, dingbat, and line/box drawing characters. Their second and subsequent characters can be any of the above characters, and/or Unicode combining characters.

We managed to rewrite an old range operator .. by using the operator declaration method thanks to the newly added infix operator to Swift.

As stated above, we can actually assign square root as a legit operator since it is a unicode math symbol.prefix operator √ {} prefix func √ (number: Double) -> Double { return sqrt(number) } let squared = √3 // 1.7320508075688

New operators are declared at a global level using the operator keyword, and are marked with the prefix, infix or postfix modifiers. Consider the operator ** found in many programming languages, but missing in swift, which raises the left hand operand to the power of the right hand operand.infix operator ** { associativity left precedence 160 } func ** (lhs: Double, rhs: Double) -> Double { return pow(lhs, rhs) } var result = 8 ** 3 // 512

Operator declaration can make a developer’s life easier as it can make the most difficult calculations into a single operator.

The example above defines a new `infix` operator called `**`. This operator does not have an existing meaning in Swift and so it is given its own custom meaning by writing a function `func ** …`. For the purpose of this example, `**` is treated as a new “to the power of” operator, or just simply *exponentiation operator*.

This implementation of ** is very similar to the implementation of *, except that this operator function multiply the left operand to itself by the number of value of the right operand.

To be a good citizen in the programming world, we should also declare the corresponding assignment operator **=:infix operator **= { associativity right precedence 90 } func **= (inout lhs: Double, rhs: Double) { lhs = lhs ** rhs } result **= 2 // 262,144.0

Since assignment mutates the original value, we defined lhs as an inout parameter.

“If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an inout parameter”.

infix operators can also specify precedence and an associativity as stated above. It is important to consider each operator’s precedence and associativity when working out the order in which a compound expression will be calculated.

Comments

Leave a Reply

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