In this unit we are going to look at how operations on objects evaluate and also we're going to learn some handy new syntax for defining operators. Previously, we defined the meaning of a function application using a computation model based on substitutions. Now we extend this model to classes and objects. The first question is if you have an instantiation of C to e_1 to e_n, how is that evaluated? The answer is, well, the class arguments e_1 to e_n are evaluated just like the arguments of a normal function, and that's it. The resulting expression is already a value, so if v_1 to v_m are values then passing them to a class constructor C gives you another value. Now let's suppose we have a class definition of a class C, which takes formal parameters x_1 to x_m, and it has a method f, which takes another set of parameters, y_1 to y_n and has a body b. For simplicity, we've omitted the types of the former parameters because they're irrelevant for the discussion here. The question is, how's the following expression evaluated? C applied to some values that are the class arguments. Select F, and then apply to some further values that are the method arguments. The answer is that we can rewrite that expression using substitutions and in this case we actually need three substitutions. Let's analyze them one by one. The first substitution here passes the actual function arguments for the formal parameters of the function, as we do that for normal functions. The second substitution passes the class arguments v_1 to v_m for the class parameters x1_ to x_n. The final substitution passes the class value c_1 to v_m itself for any references of this in the body. Let's see that with some examples. Let's say we have rational 1, 2 dot numer. That would be, according to the definition, substitute one for the class argument x, two for the class argument y, there is no the functional arguments, so the second substitution is empty, and finally, substitute rational 1,2 for this n_x. That gives simply one because x gets substituted by one, as expected. Let's do a more complex example. Let's say rational 1,2 dot less rational 2, 3; what would that evaluate to? According to the definition, we again pass one for x, two for y. Then the argument of less is irrational number 2,3, so that gets passed for the formal parameter that. The rational 12 gets passed for this. The body of less is that expression that you see here, this dot numer, that denom, less than that dot numer times this dot denom. That then would substitute to, rational 1, 2 dot numer times rational 2,3 dot denom less than rational 2,3 dot numer times rational 1,2 dot denom. If you apply the definition of numer and denom, that would substitute to 1 times 3 less than times 2 and then to true. You see that calls of methods can be described very much like cause of normal functions only that now we have not just a substitution of actual arguments for formal parameters. We have a similar substitution for the class arguments and the class parameters and finally, we have the substitution of the left-hand side from dot that value here for the reference to this in the class. Here's a variant of what we've seen before. So far, we defined all the methods of a class inside the class. That can lead to very large classes and it's not very modular. A lot of the methods we define don't really need access to the internals of a class. They could have alternatively be defined as so-called extension methods. For instance, we could ask further methods called a min and abs to class rational like this. Now, we're outside class rational, but we define an extension of a rational number r and we add the two methods, min that takes another rational number with the usual definition, and abs that takes a rational number and gives you the absolute value of that rational number. The advantage of using extensions instead of class methods is that, you can define an extension anywhere. You can define it together with the class, but you can also define it in different modules and there can be different people who can define different extensions of the same class without having to step over each other's feet. You're changing the same source code. Extensions of a class are visible if they're defined together with the class or if they're visible in the current scope where they're defined or imported. Members of an extension of a class C can be called as if they were normal methods of that class. For instance, you could write Rational(1/2).min Rational(2/3) no matter whether mean was defined as a method of class rational or as an extension of it. The idea of an extension is that it adds new functionality to a class without changing existing functionality. That has two consequences. The first is that extensions can only add new members, new methods, not override existing ones. The second is that extensions cannot refer to the internals of a class or two other members of our class via this because this is not available in the extension. You see the instance from the outside, not from the privileged access that can see this. If we look at the operations of extension methods using substitutions again, then we find that extension methods substitution works basically like normal substitution. But instead of this, it's now the extension parameter that gets substituted. Furthermore, since class parameters are not visible, they don't need to get substituted at all. We see here this example for the extension. What happens here is that, the value to the left of the dot replaces the extension parameter that was r and the argument Rational(2/3) replaces the method parameter of mean that was S. Under these replacements, we replaced the call with the body of min, which is this expression here. If you perform the substitutions, we get what we would expect this expression here. Here's a final tweak to make dealing with rational numbers more convenient. In principle, the rational numbers we've defined by our class rational are as natural as integers. But for the users of these abstractions, there's still a noticeable difference. For integers, we would write x plus y, but for rational numbers so far, we wrote r.add(s). So we used method syntax. That's in a sense of shame. If rational numbers are as natural as integers, then we should be able to use the same natural and convenient notation for dealing with them. In fact, in Scala, we can do that. We can eliminate the difference. To do that, we proceed in two steps. The first step is to relax the notion of what an identifier is. In fact, in Scala, an operator such as plus or less counts as an identifier. In general, an identifier can be alphanumeric. It starts with a letter followed by a sequence of letters or digits or it can be symbolic. It starts with an operator symbol followed by other operator symbols. It's also possible to combine the two. You can have an alphanumeric identifier that is followed by an underscore and then followed by some operator symbols. All of these would be valid identifiers in Scala, x1, *, and this funny thing here, probably not recommended to use that, vector_++ or counter_=. Since operators are identifiers, it's possible to use them as method names. Here, we use plus and times as method names for an extension of class rational. Plus is just an alias of add and times is an alias of multiply. You could also use plus and times as methods in class rational itself. That's your choice. Here, we have made the choice to use the operator names preferably as extensions. The second step is that an operator method with a single parameter can be used as an infix operator. For instance, you can write r plus s, and what it means is, you call the method plus on the left-hand value r with the argument s. The two are completely interchangeable. Likewise r less than s is just a shorthand syntax for r. method called less-than with the argument s. That explains what operators are. They're just essentially a more convenient notation formatted chords. We can use the same trick for alphanumeric methods. We might want to write, for instance, r min s, with infix operator syntax instead of r.min(s). If you want to do that, then we have to declare the infix operator with an infix modifier, so here. To be able to use min like that, you should define min with this infix modifier as an extension of class rational. That means it's usable like that. The reason for demanding and explicit modifier is that, that enforces a certain uniformity between usages. We do not want users to essentially freely mix infix and methods syntax. It is the designer of an abstraction or an under method that decides whether the method should be called infix, in which case it gets an infix modifier or whether it should be called as a normal method call, which is the more common case. Once we have operators, you need to worry about precedence. For instance, if you have 1 plus 2 times 3. How is that passed? Where do the parentheses go? What scalar does here, it has a fixed order of precedents that depends on the first character of the operator. The highest precedence is times, divide and modular, followed by plus or minus, followed by a colon, equals, bang, less-than, greater and up arrow bar. Then the lowest precedents are all letters. Min would have a lower precedence than any operator. The highest precedents are all special characters that are not in this list. You will notice that from here to here, this is actually the same precedents that operators in Java would have. Of course, in Java you have only a fixed set of operators but there precedents exactly in that order. Scalar re-uses that notion and generalizes it by allowing you to define your own operators that are not only in this set but can also use other special characters or be followed with other operator symbols. Here's an exercise for you. Provide a fully parenthesized version of this expression here. Every binary operation needs to be put into parenthesis without changing the structure of the expression. The conceptual structure of the expression should be the same with or without parenthesis. Let's see how would we go about this. Let's go from highest to lowest precedence. Which of these operators has the highest precedence? It's this one here because it starts with a question mark, which was not in our list of operators. All other special characters have the highest precedence. Question mark is one of those. That's the highest precedence, we put the parentheses like this. The next highest then would be, the plus operation here. Plus, the parenthesis would go like this. The next highest operator is the equals here. That follows up after the plus in our list of expressions so that would be this expression here. We would do the parentheses like this. That one is followed by the up arrow and that one is followed by the bar. Finally, less is the operator that remains with the lowest precedence.