7 minutes read


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 = 11000011

Operators 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 = 3

Defining 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.

There is one exception to the precedence rule. If the operator ends with the "equals" character = 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.

3 learners liked this piece of theory. 1 didn't like it. What about you?
Report a typo