0:22

It's good, programming style, particularly in functional programming, to split up a

task into many small functions. But on the other hand, names like square

root iter improve and is good enough, they really matter for only the implementation

of square root not for its usage. Normally, we would not like users to

access these functions directly, so we want to avoid name space pollution where

they would see these names even though they're not suppose to be called directly

by them. One way we can achieve that is to put

these auxiliary functions inside the function square root.

So, let me show you that, that with the worksheet.

What we have here so far is, all these functions are separate and visible on the

top level. So, what I want to do now is I take my

definition of square root and I wrap it around the functions that are on the

inside here. So, I do it like that.

I reformat, and there what do we see? So, we see the function square root that

now contains square root iter is good enough and improved, as well as the return

value of square root. Return value here comes last.

What that means is that, now our program is much cleaner.

The only function that is seen from the outside is square root.

We still have very good names for the individual sub-steps, but those are

accessible only from inside this algorithm.

So, the way we did that was using a block. A block is delimited by braces and it

contains as number of definitions and at its last element an expression that

defines the return value of the result of that block.

So, here you see a simple example. You have a defi, definition of val x as of

the result of f of three and we return x times x.

Blocks are, themselves, expressions in Scala.

So, they can be used everywhere. Other expressions can be used, including

the right hand side of a function definition.

That's what we have seen in the eclipse example here, where this block here was

the return expression of the function square root.

Now an interesting aspect of blocks is how they affect visibility of identifiers in a

program. There are two simple rules.

The first is the definitions inside a block are only visible from within the

block, not from the outside. The second rule is that the definitions

from outside the block are visible in the block as long as they are not shadowed by

definitions of the same names inside the block.

3:08

So, that means that for instance, here the name f is visible in the block, it refers

to this outer block named f. But the name x here, refers to the inner

name x not the outer name x. The inner name x shadows the occurrence of

the outer name. Let's do an exercise.

I take a small variation of the program you've just seen.

The question is, what is the value of result in this program?

Possible answers are here. Think about it and pick one.

So, let's see how we would find the answer to that one.

If we look at the value of result, then what we see is that the first thing we do

is we compute the value of x to be f of three, f is this function here.

It adds one to it's parameter so that would be give x for x the value of four.

So then, the value of x times x would be sixteen, and we take that value, and add x

to it. What's the value of x here?

Well, we're now outside the block so the value of x here is no longer visible.

And the value we do see here is that this first definition, so that would be zero.

So, the answer of the whole expression, the result of the whole expression is

sixteen. So we've seen the definitions of outer

scopes are visible inside a block unless they're shadowed.

You can use that to simplify square root by eliminating redundant occurrences of

the x parameter, which means, everywhere, the same thing.

So, what you see here in the worksheet is that the x parameter that comes into

square root is duplicated here, here, and here, but it's never changed.

It's always passed as it is before. So, we can simply eliminate it, all these

occurrences here. And eliminate the corresponding parameter

in the application. And, we have the same version of square

root, but now it's much cleaner. We have avoided the redundancy of passing

the parameter x around everywhere by using the simple trick that the value of x is

actually visible inside all these nested functions.

So, that gives you another reason for nesting things, it's not just name space

control but it's also reusing outer definitions without passing them

explicitly in parameters. Okay, one thing we haven't mentioned so

far were semicolons, simply because so far we haven't seen them.

Even though in Java every statement would be terminated by a semicolon, in Scala

they are in most cases optional. You could have written val x is equals one

with a semicolon but most people would omit that.

The only situation where you really need a semicolon is if you want to put several

definitions or expressions on one line. Then, the semicolon is needed to separate

them. So for instance, here, you have a value

definition of y equals x plus one. And then a use of the variable y in a

subsequent expression and you need the semicolon here to separate the two.

Being able to commit semicolons at the end of lines is very co, convenient, but

there's one issue with it. How would you write an expression that

spans several lines? To see the problem, consider this

expression here, some long expression, then it continued on the second line with

some other expressions. That would actually be interpreted by the

Scala compiler as two expressions. The first expression is the some wrong

expression then, it would be the implied semicolon, and then comes plus with the

other expression. There are two ways to overcome this

problem. You could write the multiline expressions

in parenthesis, because semicolons are never inserted inside a pair of

parenthesis. So, you could write some wrong expression

plus some other expression as long as you put it in parenthesis and that's fine.

Or, the other way to do that is to write the operator on the first line as the last

word on the first line because this tells the Scala compiler that the expression is

not yet finished. So, if a line ends in infix operator the

Scala compiler will assume the next line forms part of the same expression.

So, to summarize what we have seen this week, we've seen elements of functional

programming in Scala, arithmetic and Boolean expressions, conditional

expressions, if then else, functions with recursion, nesting and lexical scope.

You've learned the difference between call by name and call by value evaluation

strategies. And I believe, most importantly, you've

learned a way to reason about program execution.

You can now reduce expressions using the substitution model.

That model will be an important tool for the coming sessions.