So far our syntactic vocabulary was really minimal. Essentially all we had were functions and function applications. In this week we are going to introduce two more syntax constructs, namely conditionals and value definitions. In every language you need a way to choose between two alternatives and for that Scala has the conditional expression if-else. It looks like a if-else in Java, but it's used for expressions, not statements. You see an example here. We define an absolute function which takes an x, which is an int, and it says while if x greater or equal to zero, x. Otherwise, minus x. What you see here is that the if-else is actually an expression. It's not a statement where you have to set a variable and then return a variable. It's an expression. The x greater than zero here is an expression of type Boolean and such expressions we sometimes call predicates. So Boolean expressions are formed essentially in the same way as in Java. So you would, could write true or false as Boolean constants. Not b then is written then b for negation. Conjunction b and b. Another b would be written b and ampersand ampersand b. This junction is written with a double bar and you would have the usual comparison operators from equal, equality, inequality to all the comparisons. Generally if an expression is a legal expression in Java, then you can expect it to be a legal expression in Scala as well. Okay. So, we have seen now the syntax the formation rules of Boolean expressions, but what about their meaning and we have come to define meaning by the substitution model and we are going to do the same thing for Booleans. So how do we define meaning for Boolean expressions? Well, simply by giving rewrite rules that give you here on the left some templates for Boolean expressions and on the right how they would rewrite. Take the first one. Not true would give you false. Not false would give you true. The third rule is about and conjunction. It says true and some other expression e, doesn't matter which it is, would always be the same as e, and false and some other expression e would always be false. The rules for or are analogous to the rules for and. They have the duals of those. So true or e would then always be true of course. Whereas false or e for any expression e would be e. What's interesting about that is that and and or don't always need their right operand. That's the e here to be evaluated. Whenever you write e in a, in a sense, you can just pass the arbitrary expression. And here for instance with a false and e reducing to false, we would have that always without even looking inside the expression e. So e doesn't need to be a value. It doesn't need to be reduced to a value. And we say that these expressions use short-circuit evaluation. Of course in expressions in most other programing languages, Java included, do the same thing but now we have a concise model that shows essentially a rule for when this happens. So let's see how we would go about that. We're looking for rewrite rules for expressions of the following form. It would be if some condition Boolean. Some then part e1, else, some else part e2. One good distinction as well. The evaluation will depend on what the Boolean value b here is. So let's write one rule for where b is true. [BLANK_AUDIO]. What would that rewrite to? Well, it would rewrite to the then part e1. And conversely, if the Boolean condition is false, then the conditional which we write to the else part, e2. So those are the two rules that we are after that characterize the behavior of the conditional completely. Here's another piece of new syntax. We have seen that function parameters can be passed by value or by name and in fact the same distinction applies to definition. The def form is in a sense called by-name because its right hand side is evaluated on each use. There's also a val form which is by-value. For instance if you write val x equals 2 and then val y equals square of x, then the square of x will be evaluated right here instead of when we first refer to the name y. So the right hand side of a value definition is evaluated at the point of the definition itself and afterwards the name refers to the value. So in our case the y reference here would refer to the number 4, not to the expression square of two. The difference between val and def as a definition form becomes apparent when the right hand side does not terminate. So to do that, I can take the repo. Let's generate another looping expression again,. There we go. And now if we say def x equals loop, then nothing happens. We just defined another name for loop, whereas if I defined val x equals loop, then my repo dies and doesn't, I have to take it out explicitly with a Ctrl+C. So def x equals loop is okay, but val x equals loop will lead to an infinite loop because the right hand side loop will be evaluated at the point of the finishing. Let's do an exercise. What I want you to do is write functions and and or such that for all argument expressions x and y, and x y is the same as the double ampersand and or x y is the same as the double bars. And of course you shouldn't use bar or ampersand in your implementations. When you think about it, it's also good to think what are good operands to test that these equalities hold. Okay, let's think about how we would write the and function. First, give it signature here. So it takes two Boolean and what should it return? Well, one guideline would be let's just look at the rewrite rules for and. It says, well, if the first condition is true, then it would rewrite to the second one. Y, if the first condition is false then the result would be false. And true, false is false as expected and true true. So here we would expect true. It's true also as expected. Is true and false the only value we should test and with? Well, maybe not. What about non-terminating arguments? Let's try that. And false and loop. What would we, would we expect here? Rewrite rule says false and loop you rewritten to false so that's what we would expect here. But what we get is nothing. So, we get a, an, an infinite loop. You have to interrupt the execution by a signal. So obviously, there's something wrong here. How do we correct it? Well, if you look at it, the thing that went wrong here is that you passed the second argument y as a value parameter. If we do that then it means that it will always be evaluated, we, whereas what we need is to be able to pass it just simply as an expression. So let's try to change that. We make here the second parameter a call by-name parameter and give it the same implementation and now we can redo our expression and false loop and get false as expected.