When writing code, we often use addition, subtraction, and comparison signs. All these are called operators. For example, if we want to calculate a complex product, we can simply write it using the * operator:
scala> 319 * 3600
res0: Int = 1148400
Unlike methods, which usually have detailed names and many parameters, operators perform some basic actions on entities. Let's get acquainted with the work of operators in Scala!
Types of operators
There are different types of operators that are used in Scala. Let’s take a look at all basic types of Scala operators:
- Arithmetic operators
scala> 2 * 2
res0: Int = 4
scala> 3.1 - 2.1
res1: Double = 1.0
- Relational operators
scala> 1 > 2
res0: Boolean = false
scala> 1 <= 2
res1: Boolean = true
- Assignment operators
scala> var a = 40
a: Int = 40
scala> a /= 20
scala> a
res2: Int = 2
scala> a %= 2
scala> a
res4: Int = 0
- Logical operators
scala> true || false
res0: Boolean = true
scala> true && false
res1: Boolean = false
- Bitwise operators
scala> 60 << 2 // 60 = 00111100
res0: Int = 240 // 240 = 11110000
scala> ~60
res1: Int = -61 // -61 = 11000011Operators as methods
The task of multiplying two numbers can be solved with the .*() method:
scala> 319.*(3600)
res6: Int = 1148400
To be precise, the * operator calls the .*() method of Int class.
scala> 319 * 3600 // Scala calls 319.*(3600)
res0: Int = 1148400
Simply saying, the differences between operators and methods lie in syntax. In Scala, operators are types of methods. And there are two forms of operator writing that you have already seen:
- Infix, which means the operator (or method) sits between two operands;
- Dot-notation, which is basically calling a method of a class.
Here is what they look like:
scala> 1 + 2 // infix
res0: Int = 3
scala> 1.+(2) // dot-notation
res1: Int = 3Defining and using operators
Let's imagine that we have a class called Point.
Mathematically, you want to be able to add points (by adding x and y coordinates). But if you try to use the addition operator, our code won't compile:
class Point(val x: Double, val y: Double)
val pointA = Point(1.0, 3.0)
val pointB = Point(2.0, 4.0)
pointA + pointB // does not compile
If you define the addition method +, you will get the sum of the coordinates of pointA and pointB.
class Point(val x: Double, val y: Double):
infix def +(that: Point) = Point(x + that.x, y + that.y)
val pointA = Point(1.0, 3.0)
val pointB = Point(2.0, 4.0)
pointA + pointB // Point(3.0, 7.0)
We usually write verbal names for methods that describe their logic. But sometimes, when the operation is very simple or its meaning is obvious from several characters, it's enough to use operators like in the Point example above.
Note the infix keyword in the Point class. We can add this keyword in Scala 3 so that the method is used exactly in infix style and the code is more consistent.
Precedence
Imagine a mathematical expression 1 + 2 * 3. You know that multiplication is a higher priority action, so the result is 7. There is also a rule in Scala by which the order of calculation is determined.
Expressions that use multiple operators will be calculated based on the priority of the first character. The higher the first character of a method in the list below, the higher the priority:
- (all other special characters)
* / %+ -:= !< >&^|- (all letters,
$,_)
If the first characters are on the same level, the order of evaluation is left to right. The expression a +++ b *** c will be calculated as a +++ (b *** c) because * has a higher priority than +.
When multiple operators with the same precedence appear in an expression, associativity determines how operators are grouped. The last character of a method defines associativity. Methods that end with the : character are invoked by passing the left operand to the one on the right:
scala> 1 :: 2 :: Nil
res0: List[Int] = List(1, 2)
// The entry is equivalent to
scala> (Nil.::(2)).::(1)
res1: List[Int] = List(1, 2)
Methods that end in any other character are invoked in the opposite way: the right operand is passed to the left operand.
= and it's not one of the comparison operators (<=, =>, ==, !=), the precedence is the same as that of a simple assignment =:
scala> var num = 10
num: Int = 10
scala> num += 2 * 10
num: Int = 30
Conclusion
In this topic, you learned that operators in Scala are method calls. They call methods, which in turn perform a required operation. Thanks to this, your code looks more readable and is easily understood by others. Scala has no special notion of operators: even an expression like 2 + 1 is just calling a member of an instance. Any method name can have an infix like that. You also had a look at two forms of operator writing in Scala: infix and dot-notation, and learned about the precedence of operators that determines the order of calculation.