0:00

Now that we've seen how we can encode primitive types as classes, the only two

fundamental types of values that are left are instances of classes and functions.

What we're going to look at in this session is how function types relate to

classes, and how function values relate to objects.

In the last session, we've seen that Scala's numeric types and the Boolean type

can conceptually be implemented like normal classes.

But what about functions? Are functions special or are they also

just objects? In fact, function values are treated as

objects in Scala, not just conceptually, but in reality.

What happens here is that the function type a arrow b is really just an

abbreviation for the class scala dot function one ab.

And that class is roughly defined, as you can see here.

In fact, function values are already treated as objects in Scala not just

conceptually, but really. The function type A arrow B is just an

abbreviation for the class scala.function1, two type parameters, the

A and the B. And that class is roughly defined as

follows. So it's a trait in pack of Scala.

It takes the two type parameters, A and B. And it has a single method which is called

Apply. So apply the function to an argumentix of

type A, yielding a result of type B. So functions are really objects with apply

methods. What you've seen here was the definition

of four functions of a single argument, but there are also classes, function two,

function three and so on, for functions that take more parameters.

Currently we have those function traits until 22 parameters, but in the future

there might be more, or we might be more flexible in that.

1:58

Okay, so we've looked at function types. What about function values?

Let's look at an anonymous function like the squaring function here, which takes

and X and returns X times X. What would that expand to in this

object-oriented view of functions? Well, it would be a new class that we

create here called this anonfun, I assume that the name is not used otherwise in the

program. And that would be a subclass of my

function one trait, Int, Int are the argument types.

And the apply method then, would be one that takes an integer and returns the

square of its argument. So that was the class that implements this

behavior. Now all that's needed to do is create an

instance of that class. That would be the object that represents

this function here. So creating an instance is simply new and

unfun. In fact, that definition is again quite

common and there's a shorter syntax for it.

It's called anonymous class syntax. So what we can do is, we can take

essentially this part here And leave out the name, so we write just, new function

one, and int, and the definition of that class.

So that create a new instance of a class that I haven't bothered to give a name.

That anonymous class syntax you actually find in Java as well, so both Java and

Scala have the same syntax in, in for, for this construct.

3:32

Okay. So now we've seen how we represent

functions. But, what about then applications of these

functions or function calls? So, let's say we have a function that was,

started life as this anonymous function. So, it's an object.

And now we apply it to two concrete arguments, A and B.

What would that expand to? Well, what it would expand to is simply

calling the apply method of the function value with the same arguments.

So a complete object oriented translation of this code here, where you first create

an anonymous function and then apply that function to the value seven would be, we

create a anonymous class instance, with an apply method, name it F, and then call the

apply method of F with the argument seven. So now you see that functions are objects.

Does the same hold for methods? For instance, this apply method here.

Would that, by itself, be an object? Well, that can't very well work.

Because if apply was an object. Well, it would be an instance of this

function class, which would be, have an apply method, which would be an object,

Which would be an instance of this function class, which would have an apply

method. You see the problem.

We would get an infinite expansion. So what happens instead is that methods

such as Def, F, Boolean. So anything that's defined with a Def are

not, themselves, function values. But if the name of a method is used in a

place where a function type is expected, it's converted automatically to the

function value. And the conversion is just that we create

an anonymous function like this one here. Which, where we say, well, give me an

argument, and I apply the method to the argument.

That anonymous function value we've seen how that expands to this new anonymous

class. New function one in boolean with the apply method.

So that's how. Functions really are treated in Scala.

A technical term which you don't need to remember, but I just give it for

completeness here. So this transformation here that converts

the name F to this anonymous function, It's called, in lambda, calculus, eta

expansion. So if you hear sometimes the word eta

expansion, then you know now what it is. Let's do an exercise.

In package week four, where we have defined previously the list class with its

subclasses, I want you to define an object list with

some functions in it. And the idea would be that users will then

be, create lists of length, Zero, one, or two just with the syntax.

So list of open parens, closed parens with the empty list.

List of one would be the list of the single element one.

And so on. So let's see how we would solve this.

I've put up the list class that we've developed previously so the task was to

develop an object together with that class that would give us that syntax that we

could just call list of twelve. Lets say.

So how would we do that. So idea is if we look at that syntax list

is used in function possession. So what this would really expand to you

know that would be list.apply12. So that means that we're asked to define a

method called Apply. And in that case it would take two

arguments. A, let's call it X1.

Of type T and X2 of type T, so the T can be arbitrary, we have to parametrize apply

with it. Then would return a list, so result type

is list of t. And it would then return a list that

consists of these elements. So that would be new of cons of x1 and new

of cons of x2 and new of middle. And for the other two, for list of one and

list of zero, the result would be analogous.

So, I leave out list of with single elements.

But, for the empty list, I simply have an apply method.

It takes no arguments. I would give us.