0:00

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.

0:16

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.

0:42

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.

1:00

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.

2:57

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.

4:07

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.

4:44

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

5:41

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.

6:13

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.

6:50

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?

7:55

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?

8:09

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.