(bright music)
Frank: Hello, everyone.
Welcome back.
I am in the Section21 workspace
and I'm in the Stateless Lambda project.
In this project, I've got some examples of stateless lambda
that I'm using in different ways
and I've got some using value parameters,
reference parameters, passing objects,
and returning lambdas and so forth.
So I'll go through them one at a time.
And I've already gone ahead and built and run.
So you can see the run over here on the right
and I'm just gonna walk through this.
There are seven little test functions that I've written
that kind of exercise a whole bunch
of different combinations of stateless lambdas
so you can get a pretty good feel for them.
But before I talk about those little functions,
let's talk about what's going on here.
So it's important to keep in mind
that we are working with stateless lambda expressions.
So that means that the capture lists are empty.
They're gonna be empty for all of the examples in here.
You can see here that I've included iostream,
string, and vector.
These are just common includes
that I'm gonna use throughout.
I'm also including algorithm
which gives us the standard template library algorithms.
And here is the functional header.
This is the one we need for stooge function
and this is the one I mentioned
in the slides in the previous lecture.
So those are my includes.
And here I've defined a real simple class person,
and this is the one that I'm going to use
in some of the examples where we're passing objects
within the lambdas.
So, here's my class Person.
I have a friend function
that's just my overloaded insertion operator
that lets us display these person objects to a stream.
And you can see it implemented down here.
Nothing new.
This is all stuff we have already done before.
You can see that the person class has these two attributes,
a name, which is a stooge string, and the person's age.
Really simple.
We've got a constructor that expects a name and an age.
We've got a copy constructor.
We've got a destructor, which I'm just letting the compiler
create the default for me
since there's nothing special to do here.
And then right here I've got my getters
and my setters, right?
I've got my get_name, set_name, get_age, set_age.
Okay, so now that that's outta the way,
you can see it's really straightforward.
I'll refer back to this when we get to it.
You can see down here in my main
what I'm doing is I'm calling these functions
all the way from test one all the way to test seven.
So I'm gonna walk through them one at a time.
And each one adds a little bit and changes a little bit
just so you can get a good feel for the differences
between the stateless lambda expressions
that I'm gonna show you.
All right, so let me start with test one.
I'm just gonna scroll up to it.
And here is test one.
And you can see over here in the output right up here,
that's the output for test one.
So that's what I'll be referring to as I walk through this.
Real simple.
We have no capture list.
None of these guys are capturing anything
that's why they're stateless.
We have no parameters.
And the body of the lambda just says cout Hi in this case.
So it's just gonna display Hi.
We are instantiating it right there.
It's really important that we use that.
Otherwise, it's not doing anything.
At this point now ,that lambda expression will execute
and Hi is displayed.
You can see it right there.
Same idea with this guy here
except now we've got a parameter.
We've got an integer parameter x.
Again, stateless, right?
So this is our parameter x and we are displaying x.
That's the body of the lambda.
So whatever value is in here will be displayed here
when we display the output statement.
Now, same idea over here.
We're calling that lambda and we're passing in 100.
This 100 is being passed in here, right?
So now x gets the 100.
And when this body executes, we're going to display 100,
and that's exactly what's happening here.
All right, so let's look at the third example.
Same idea, except now I've got two parameters.
I've got an x and a y.
So we're displaying the x plus the y over here.
We're just adding them up.
We're displaying the sum.
You see the 100 is being passed over here to the x,
the 200 is being passed into the y.
All this is happening by value, right?
There's no references in here.
This is by value.
So we're doing copies.
And what we're gonna do is 100 plus 200,
and this guy will display 300,
and that's what you're seeing right here.
Okay, so that's a real, real simple example
of lambda expressions.
Simple but not very useful, right?
You can see it's kind of silly.
Why would you do this, you know?
Can't we just it?
It's kind of contrived if you will,
and nobody really writes lambda expressions this way.
It's more what I'm gonna show you in a little bit.
But this gives you a good feeling for the structure
and the syntax of the lambda expressions.
They're not complicated.
You've got the capture list.
You've got the parameter list.
You've got the body of the lambda.
That's what it's like.
It can get more complicated when we're doing captures,
and we'll do that in the next video.
Okay, so let me show you now test two.
Let me close this piece down.
And here I've got test two.
And you can see here what I'm doing
is using values and references now for the parameters.
So it's gonna be a little bit different
because we're gonna be using reference parameters.
In this case, I've got a variable here.
What I'm doing over here is I've got a lambda expression
and I'm assigning that lambda expression to a variable.
This is the same thing as saying something
like an x equals, you know, three plus five.
I'm evaluating that expression and assigning it to x.
Later on, when I use x, I'm gonna be using eight, right?
This is exactly the same idea.
This is a variable l1.
What's important here is I'm using the auto keyword
to tell the compiler, hey, compiler,
you figure out what the type of this thing is.
It's a lambda, it's not an ant, it's not a void,
it's not a double, it's a lambda.
Let the compiler figure out how to do it.
Same idea, it's the same lambda as before.
Notice the difference though.
We don't have that piece at the end, right?
So what we're doing is we're creating that lambda expression
and we're assigning it to l1.
Now, whenever I want to call it,
now I could just say l1 with the perens.
It looks just like a function call and essentially it is.
Remember we talked about overloading
the function call operator?
Well, that's really what's happening behind the scenes.
So at this point right here,
not here, but right there on line 45,
that's when we get the Hi here.
So hopefully that's clear.
And in this case now, let's look at lines 47 and 48.
We have two integers, num1 and num2
and each one has been initialized to 100.
I'm creating another, variable l2 right here
which is also a lambda, right?
Again, stateless.
I've got two parameters by value
and I'm doing the same thing, x plus y,
same example I used earlier.
But now look what I'm doing.
I'm calling it.
So I'm calling, I'm pass l2
and then I'm passing a 10 and a 20.
So the 10 gets over here and the 20 comes over here.
This guy's gonna be 30 and that's what's gonna display.
Right here, we get that 30 displayed.
Now, those are two integer literals
and that's perfectly valid.
In this case, we've got num1, num2.
So now we're gonna pass in,
instead of 10 and 20, 100 and 100, right?
So we're gonna display 200
which is what's being displayed here.
Remember, this is passed by value, this is value parameters,
so we're making copies of these values.
So now let's take a look at an example with some references.
And now we are right here on line 54
and we've got the same idea.
I've got a variable, l3, and we've got two parameters now.
The difference is now x is a reference parameter.
We know what those are, right?
We've talked about 'em already in the class.
It's basically an alias to an actual parameter.
And I have y, which is a value type parameter.
And all this lambda does,
it's gonna display x and then it's gonna display y.
But within the body of the lambda, we're changing x and y.
Now, this is really important to understand.
When I'm changing x, I've got a reference.
So that means that the actual parameter
is going to be changed to a 1,000.
When I change y to 2,000,
the local copy of y will be changed, so not the actual.
So let me show you what that looks like when I call this.
So at this point,
remember we're gonna call this with num1 and num2.
And if you remember, num1 and num2 are 100 each, right?
So what's gonna happen is, actually, let me clear this up
and do this one more time so it's clearer.
I've got num1 and num2 which is each 100.
Now I'm gonna call l3 with num1 and num2.
num2 is a 100.
So that becomes the y and that's copied.
But num1 is a reference, right?
So what happens is this guy now
refers to the actual parameter up here.
This guy's just local, okay?
That's really important.
It's a very important distinction.
We learned about this when we used functions.
It's exactly the same thing.
So at this point, we're gonna execute this code.
This code is going to change,
and first of all, it's gonna display x and y
which are 100 and 100, right,
'cause I haven't changed them.
You can see it right there.
Then it's gonna change x to 1,000.
That's this guy right here.
So this guy's gonna be 1,000.
it's gonna change Y to 2,000, which is this guy.
It's irrelevant 'cause that's gonna go away
when the lambda is finished.
Now we're done.
So what happens is all this gets cleaned up
and the only thing that's left behind
is this guy's 1,000 num1, is 1,000, num2 is 100.
So when we come back,
we're just gonna display num1 and num2.
And you can see right here we're getting the 1,000,
which we changed, and the 100.
Okay, hopefully that's pretty clear.
If not, just walk through it yourself just like I did
and that way you'll get a really, really good feeling
of what's going on here.
Okay, so let's move on to test three.
All right, so what are we doing in test three?
We're basically doing the same thing we did in test two
except we're using objects now instead of primitive types.
The other example we used integers.
So what's going on here?
Well, I'm gonna create a person object called stooge,
and that would be Larry and Larry's 18 years old.
And then I want to display stooge here.
So right on line 68, I'm in test three,
this is what's happening right there.
That one line is executing.
Larry 18, just what we expect.
Now I'm creating a lambda, I'll call it l4.
In this example here, we are passing in a person object.
This is really important.
This is by value.
So what happens here, a copy.
And how do we copy objects?
Copy constructor.
The copy constructor will be called
and it'll create a new copy of that object.
That copy of the object will be alive.
Within the body of the lambda,
we can change it all we want in there
and it's not gonna affect the actual.
That's really important.
Same thing that just happened with integers,
but now we're dealing with objects.
So now what am I passing into l4 stooge.
So now what's happening is I get a new version, right,
a new copy of that stooge object.
So inside this function here I have p,
and p would be Larry 18,
which is totally separate from this Larry 18.
This is a new copy.
And that's active, so I'm gonna display it
and it's gonna display right there.
That's the second display statement, right?
The first one was up here.
And that's it.
Stooge did not change, right?
It can't change because we made a copy of it.
Now let's do it by reference and see the difference.
I'm right here on line 75.
Remember we've already executed that one
and we've executed that statement right over here.
So I'm over here.
l5, again stateless, one parameter, a reference parameter.
Really, really different now, right?
No copy constructor, no copy.
We're gonna get an alias.
At this point, we also said it's constant.
So if we try to change that p object in here in the body,
we won't be allowed.
The compiler will give us an error.
So let's do this, l5.
We're gonna pass in stooge.
We don't make a copy of it.
This p refers to the real one.
So again, very efficient.
I can't change it because it's cons,
so I get the best of both worlds, right?
When I'm in here, I'm displaying p.
p is right there, Larry 18.
And you can see that third statement executes right there.
So that's passed by reference.
Now, let's do pass by reference
but actually modify the object,
and that's what this last statement here does.
Let me scroll up just a little bit
so you can see a little bit better.
So remember at this point we've done this, this, this
and we are right here now.
So my lambda variable is l6.
I'm passing in a person object by reference.
Really important, notice there's no cons over here
like there was over here.
I'm able to modify that and I'm gonna modify that.
So I'm gonna pass in stooge.
This p will be stooge, right?
So it's going to be a reference to stooge
and it's defined up there.
It's scrolled off, but it was stooge and it was Larry 18.
That's my object.
But now look what I'm doing in the body.
I'm saying, hey, set the name to Frank.
So I'm changing Larry to Frank and change the age to 25.
So I'm changing the 18 to a 25.
Then I'm displaying p.
Well, p is a reference to this guy, right?
And notice right there, what happens?
Frank 25.
Then once I finish, I'm gonna display stooge now.
Well, that is stooge, right?
So I'm gonna get the same thing.
So there's proof here, right, in both cases.
There's the proof that we actually changed
that stooge variable out there from within the lambda
because of that reference parameter.
Okay, so this video's getting a little bit long now.
So what I'm gonna do is I'm gonna stop this video here
and we'll continue with test four in the next video.
I'll see you there.