© Radoslava Leseva Adams and Hristo Lesev 2016

Radoslava Leseva Adams and Hristo Lesev, Migrating to Swift from Flash and ActionScript, 10.1007/978-1-4842-1666-8_18

18. Operators

Radoslava Leseva Adams and Hristo Lesev2

(1)London, UK

(2)Kazanlak, Bulgaria

We start our exploration of the Swift language with a look at the operators it offers. You will find that your ActionScript experience has prepared you for most of what’s to come in this chapter. The majority of operators look the same and follow the same syntax and rules for associativity and precedence you would expect.

The first part of the chapter lists operators that both Swift and ActionScript share. We then move on to a few operators that will be new to an ActionScript developer. At the end of the chapter we will see how you can define your own operator implementations or even create custom operators using operator overloading.

Operators You (Almost) Know from ActionScript

In all fairness, even among the operators you are familiar with you will find the occasional subtle difference between Swift and ActionScript. The list points these out in order to minimize surprises when you code.

Comparison Operators

Most of the comparison operators look and behave the way you would expect them to.

  • Equal to operator: (a == b)

  • Not equal to operator: (a != b)

  • Greater than: (a > b)

  • Less than: (a < b)

  • Greater than or equal to: (a >= b)

  • Less than or equal to: (a <= b)

The following two operators however have a slight difference, although they look the same in both languages:

  • Identity operators: (a === b) and (a !=== b)

The ActionScript counterparts of the identity operators are called strict equality/inequality and let you compare object references as well as primitive values. In Swift, however, they only serve to compare references: you can check if two constants or variables refer to the same object, but not if two integers or strings have the same value.

Assignment Operator (a = b)

Just like in ActionScript, the assignment operator , well, assigns a value to a variable. And there is a subtle nuance in its behavior: unlike in ActionScript, the operator does not return a Boolean result. It does not return a result at all.

In other words, the code in Listing 18-1 will have different consequences in each language: in ActionScript, the if (a = 3) check will return true, causing the code after the if statement to always be run; in Swift this expression will simply not compile.1

Listing 18-1. In Swift the Assignment Operator Does Not Return a Result
if (a = 3) {
    // The code after the if statement will always execute in ActionScript,
    // but won't even compile in Swift.
}

Compound Assignment Operators

These look and feel the same in both languages:

  • Addition assignment: (a += b)

  • Subtraction assignment: (a -= b)

  • Multiplication assignment: (a *= b)

  • Division assignment: (a /= b)

  • Remainder assignment: (a %= b)

  • Left shift assignment: (a <<= b)

  • Right shift assignment: (a >>= b)

  • Bitwise AND assignment: (a &= b)

  • Bitwise XOR assignment: (a ^= b)

  • Bitwise OR assignment: (a |= b)

  • Logical AND assignment: (a &&= b)

  • Logical OR assignment: (a ||= b)

Arithmetic Operators

A new thing here is that the arithmetic operators will not allow overflow or underflow in their result. If either of these occurs, you get a runtime exception EXC_BAD_INSTRUCTION thrown. A bit disturbing at first, but quite handy for catching overflow or underflow errors as close to the crime scene as possible, instead of wasting ages debugging weird behavior down the line.

If you want to enable overflow behavior, you need to explicitly use the overflow versions of the addition, subtraction, and multiplication operators: the section “Overflow Operators,” later in this chapter, shows you what they look like.

  • Addition: (a + b). Adds expressions. Note that you can use it to concatenate strings and arrays, as well as numbers.

  • Subtraction: (a - b). Subtracts numeric expressions.

  • Multiplication: ( a * b). Multiplies numeric expressions.

  • Division: (a / b). Subtracts numeric expressions.

  • Remainder: (a % b). The remainder operator has the same specifics both in ActionScript and in Swift, including support for floating-point operations and how it handles signed operands.

  • Unary minus and plus operators: (-a) and (+a). These are fancy names for the minus and plus sign you put in front of numeric values and variables and do exactly what you would expect them to: the minus sign toggles the sign of the operand and the plus sign returns its operand as it is without changing it. No difference between Swift and ActionScript.

A word about two pairs of operators that you may (or may not) miss in Swift: the increment and decrement operators: (a++), (++a), (a --) and (--a). Despite being initially part of the language, they have been voted out of Swift 3, in order to keep code simple and easy to read. As you know from ActionScript, when you use these operators you need to keep in mind the difference between their prefix (++a) and postfix (a++) versions: the prefix version increments/decrements its operand and returns the modified value, while the postfix version returns the operand and then modifies it. The relative conciseness that you get from using these operators was deemed not worth this complexity when reading and maintaining code or when learning how to program from scratch with Swift as the first language.

Logical Operators

Following are the three logical operators you can use in Swift:

  • Logical NOT: (!a)

  • Logical AND: (a && b)

  • Logical OR: (a || b)

There are no surprises here if you are used to how these work in ActionScript. This includes how logical operators are combined in compound expressions and the use of lazy evaluation.

What Is Lazy Evaluation?

Here is a brief reminder of how it works. If the first operand in a logical OR statement evaluates to true, the rest of the expression after the OR will not be evaluated, as the result will always be true. The same thing happens if the first operand of a logical AND statement evaluates to false: the result of the whole expression is then assumed to be false and no further evaluation is done.

This makes code like that in Listing 18-2 and Listing 18-3, if not a good habit, at least safe to write.

Listing 18-2. Lazy Evaluation in ActionScript
// ActionScript code
var s : String = null;
if ( null != s && 0 != s.length )
Listing 18-3. Lazy Evaluation in Swift
// Swift code
var s : String? // s is nil
if nil != s && 0 != s!.characters.count

Without lazy evaluation we would expect to get a runtime exception from both if statements, as the operands to the right of the logical AND (&&) try to access properties of null/nil objects. The rules of lazy evaluation, however, mean that both the ActionScript and the Swift compilers will stop after evaluating the first operand: null != s and nil != s, respectively. Because this results in false, the rest of the logical AND expression will be discarded, its final result will be assumed to be false, and the problematic code will not be run, thereby sidestepping the potential exception.

Bitwise Operators

Bitwise operators let you deal with data on the level of individual bits.

  • Bitwise NOT: (∼a)

  • Bitwise: AND (a & b)

  • Bitwise OR: (a | b)

  • Bitwise XOR: (a ^ b)

  • Bitwise left and right shift: (a << b) and (a >> b)

Although all of these look the same in both languages, there are a couple of differences worth noting. First, unlike ActionScript, Swift doesn’t convert the operands of the bitwise operators to 32-bit signed integers before performing the operation. And second, where ActionScript has a separate operator to deal with right shift for unsigned integers (>>> and its compound version >>>=), Swift does not. Instead it changes behavior depending on the type of operands you pass to the shift operators.

Ternary Conditional Operator

The name of this operator probably sounds new, but it’s just another name for your old friend, known simply as conditionalin ActionScript. It looks like this:

condition ? result1 : result 2

This is shorthand for

if condition { result1 } else { result2 }                  

New Operators in Swift

Here we leave the common ground and explore a handful of operators without parallels in ActionScript.

Nil Coalescing Operator

The nil coalescing operator is the epitome of conciseness in Swift. This is what it looks like:

var c = a ?? b

It is shorthand for: c = ( a != nil ) ? a : b.

Or, in English: unwrap a; if a is not nil, assign its value to c, otherwise assign the value of b to c. This has implications on the types of the two operands: a needs to be optional, but b cannot be. Instead, b needs to match the type that the optional a operand stores.

Tip

For details on value unwrapping have a look at the section “Optionals” in Chapter 19 .

Range Operators

Range operators let you define an interval or a range of values and thus are useful tools for for loops, pattern-matching if and case statements (more on these in Chapter 20 ), and working with subsets of strings and arrays. You can choose between two range operators, depending on whether you need to include one or both boundaries of the range:

  • Closed range operator: (a..b)

  • Half-open range operator: (a..<b)

The closed range operator defines an interval from a to b, including both a and b. As the example in Listing 18-6 shows, the value of the lower end of the interval is expected to be no greater than the upper value, otherwise you get a runtime error (Listing 18-4).

Listing 18-4. Closed Range Operator Syntax
// this prints out the numbers from 1 to 3:
for i in 1...3 { print ( "i = (i)" ) }


// this results in a runtime error:
for i in 3...1 { print ( "i = (i)" ) }

In contrast, the half-open range operator defines an interval from a to b, including a, but not b. The same rule applies here, as we saw with the closed range operator: the value of a should be no greater than the value of b (Listing 18-5). Writing (a..<a) defines an empty range .

Listing 18-5. Half-Open Range Operator
// this prints out the numbers from 1 to 2:
for i in 1..<3 { print ( "i = (i)" ) }

Pattern-Matching Operator (∼=)

The pattern-matching operator works with ranges and tells you if a value is in a given range. The following line evaluates to true if row has a value between 0 and 2, including 0 and 2:

0...2 ∼= row

Overflow Operators

The overflow operators behave just like normal arithmetic operators, which allow value overflow or underflow. As you saw earlier in the section “Arithmetic Operators,” the default versions of the addition, subtraction and multiplication operators in Swift will throw an exception if their result over- or underflows. To opt out of this behavior you need to explicitly use these versions of the operators:

  • Overflow addition: (a &+ b)

  • Overflow subtraction: (a &- b)

  • Overflow multiplication: (a &* b)

Like in ActionScript, when a value is too big for the number of bits that its type can hold, the extra bits get truncated, causing the value to wrap around from the minimum value to the maximum or vice versa.

Operator Overloading

Function or operator overloading is not part of ActionScript. In many other languages, including Swift, you can have multiple functions with the same name but different signatures: the functions may differ in the number or types of arguments they take and/or in the type of the result they return. These namesake functions are called overloads. The compiler decides which overload should be executed based on how you call it.

In the context of operators, it is convenient to be able to apply an operator to any type, including your custom types that the operator in question may not support. Providing your implementation (overload) of the subtraction operator, for example, lets you use the more concise and expressive a – b, instead of an equivalent function call: myCustomSubtractionFunction(a, b), where a and b are instances of a type you have defined.

Like using salt in cooking, operator overloading is helpful in carefully considered amounts. Just because you can make + or == do whatever you want, it doesn’t mean you should. Providing a dramatically different behavior for an operator would be at best confusing for your fellow programmers and at worst might break its relationships with other operators and lead to strange results in your code.

Operators differ in how many operands they take and how operands are positioned with respect to the operator: on its left, on its right, on both sides, and so on. This leads to difference in the syntax for overloading each sort of operator.

To demonstrate this, we will go through a simple example. Let us declare an enumeration, called WeekDay, which represents the days of the week (Listing 18-9). Each member of the enumeration has a raw value assigned to it, starting with 0 for Monday.

Listing 18-6. An Enumeration, Which Represents the Days of the Week
enum WeekDay : UInt {
    case Monday = 0, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}
Note

Chapter 22 covers enumerations in detail.

Overloading an Infix Operator

Infix operators are put in between their operands (e.g., the addition operator: a + b).

If you tried to use the addition operator to add a number to a WeekDay instance at this point, the compiler would issue an error. You need to define a version of the global addition operator that will make sense to the Swift compiler (Listing 18-7).

Listing 18-7. Overloading the Global Addition Operator to Work with WeekDay Instances
func + (left: WeekDay, right: UInt) -> WeekDay {
    // This ensures that we don't go over the values allowed by WeekDay, so:
    // Tueday + 6 should return Monday
    let dayNumber = (left.rawValue + right) % (WeekDay.Sunday.rawValue + 1)
    assert( WeekDay.Monday.rawValue ... WeekDay.Sunday.rawValue ∼= dayNumber )


    return WeekDay(rawValue: dayNumber)!
}


// This allows you to do the following:
let weekDay = WeekDay.Tuesday
let newWeekDay = weekDay + 6 // newWeekDay is WeekDay.Monday

Overloading a Compound Assignment Operator

The operator overload in Listing 18-8 allows you to do this: weekDay += 4. The operand on the left of the operator—in this case the first argument of the operator function—is the one that will be modified. This is why it’s declared inout.

Listing 18-8. Overloading the Compound Assignment Operator
func += (inout left: WeekDay, right: UInt) {
    // We sneakily take advantage of the addition operator
    // that was overloaded in the previous example:
    left = left + right
}
Note

The Swift 3 syntax for this function declaration is func += (left: inout WeekDay, right: UInt) {/*...*/}. See Chapter 17 for details on inout parameters.

Overloading a Prefix or a Postfix Operator

Building on the same example , let us have a look at how you can make this work: ++weekDay. The syntax for defining an overload to a prefix operator is similar to what you saw with infix operators, but it includes the keyword prefix (Listing 18-9).

Listing 18-9. Overloading the Prefix Increment Operator
prefix func ++ (inout weekDay: WeekDay) -> WeekDay {
    weekDay += 1 // Making use of the += overload
    return weekDay
}

This function is global too, instead of being a method of WeekDay, as it provides an overload to the global prefix increment operator.

Note the inout keyword in front of the argument in the function signature. As its name suggests, it means that the weekDay argument is to be treated both as an input and an output parameter: its value is taken by the function, modified, and, when the function exits, replaces the original value of flight.

Overloading a postfix operator has the same syntax, except that it uses the postfix keyword instead. Also, when overloading a postfix operator you must remember to return the value that the operand has before it gets modified.

Caution

The increment (++) and decrement (--) operators are no longer part of the language since Swift 3.

Providing a Custom Operator

Finally, in Swift you can define your own custom operators. The rules are as follows:

  • You are allowed to use some ASCII characters that are employed for conventional operators (/, =, -, +, !, *, %, <, >, &, |, ^, ?, ∼) and some Unicode characters.

  • There are certain characters and tokens that are reserved and you can’t use, for example: =, ->, //, /*, */, ., the prefix operators <, &, and ?, the infix operator ?, and the postfix operators >, !, and ?

  • You must first provide a declaration of your custom operator, using the operator keyword and then define an overload for that operator.

Tip

For a complete list of the symbols you can use in a custom operator, as well as how to ensure consistent precedence and associativity for your custom operators, see the “Basic Operators” and “Advanced Operators” chapters in Apple’s The Swift Programming Language ( https://goo.gl/Xj8aef ).

This last example declares and overloads a custom operator that will reset a WeekDay instance to 0 (Monday). Let us say that we want the operator to be postfix and to be used like this: weekDay^^ (Listing 18-10 ).

Listing 18-10. Defining a Custom Operator
// First, declare the operator
postfix operator ^^ {}


// Then overload it to handle WeekDay
postfix func ^^(inout weekDay: WeekDay) -> WeekDay {
    // Store the original value of the operand:
    let originalWeekDay = weekDay


    // Then modify the operand:
    weekDay = WeekDay(rawValue: 0)!


    // Finally, return the original value,
    // as we are defining a postfix operator:
    return originalWeekDay
}
Note

The Swift 3 syntax for this function declaration is postfix func ^^(weekDay: inout WeekDay) -> WeekDay {/*...*/}. See Chapter 17 for details on inout parameters.

Again, excercise your judgment when you define custom operators. Keeping code readable and easy to grasp at first glance is often worth more than making it short.

Summary

This chapter showed you how similar operators in ActionScript and Swift are and highlighted the subtle differences that Swift has here and there. It also introduced you to operators that are new in Swift and showed you ways of defining operators for your own custom types.

The next chapter will focus specifically on types and type safety in Swift.

Footnotes

1 Why is it significant that the assignment operator does not return a result in Swift? More often than not statements like if (a = 3) are a result of a typo, where the intention was to write if (a == 3). So in languages like ActionScript it’s a good habit to put the constant, or the more constant of the two operands, to the left of the comparison operator: if (3 == a). That is, if one of your operands is nice enough to be constant. Why? The ActionScript compiler will let you know that you have made a typo if you mistakenly wrote if (3 = a). The Swift compiler spares you the need to trick it and will instead issue a compiler error if you ever tried to check the result of an assignment operation by mistake or intentionally.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset