Learniverse

Die Kraft der Faulheit in der Programmierung

00:00

Thanks for coming here. Let's talk about, let's get lazy, exploring the real power of screams.

00:20

My name is Ben Katsubramanyam. I'm going to talk about what is lazy valuation, what are some of the reasons why we are really interested in it.

00:28

And we'll talk about how laziness can be implemented in a number of different ways.

00:33

But before we get started, just a quick show of hands. How many of you are lazy?

00:37

That's great. I just want to make sure I'm in the right place. Fantastic.

00:41

So let's talk about, you know, lazy valuation. What does it really mean to be lazy?

00:45

Well, when it comes to functional programming, we often hear people talk about how immutability is so important.

00:52

We talk about higher order functions. And in my opinion, the problem with such discussions, and I've done this also myself,

01:00

is telling programmers that they should program immutability is like telling children they have to eat vegetables.

01:06

And nobody likes it. So why do we really care about immutability, water some of the reasons?

01:11

And I want to really talk about why that is so critical to do.

01:15

As you're listening along, if you have questions, I do request you to raise the questions through the app,

01:20

and we will have the questions at the end of the session, and also take your time to rate the app talk as well towards the end.

01:27

So let's talk a little bit about what is the reason for such importance to immutability and such.

01:33

Well, I'm going to actually ask the question, what is really functional programming?

01:38

And I'm going to argue that functional programming really is little to do with immutability.

01:44

Functional programming really is little to do with higher order functions.

01:48

To me, the really core features of functional programming is two things.

01:52

One is that we are really interested in functional composition.

01:56

And functional composition gives us the ability to express our code really well in terms of flow of the data through processing that we do.

02:06

And I'm going to say one of the most critical aspects of this is,

02:10

functional composition plus lazy evaluation.

02:14

And I remove laziness from this equation.

02:18

I think it's pretty pointless to talk about functional programming.

02:21

So lazy evaluation is probably one of the most critical aspects of programming functionally in a sense.

02:28

And so laziness is very absolutely critical.

02:31

Look at any sensible functional programming language you will see lazy evaluation in it.

02:36

So this is one of the most critical things to do consider.

02:39

But when it comes to programming, there are different programming languages out there.

02:44

And unfortunately the world has really settled upon a few mainstream languages.

02:50

There are literally so many languages, which is thousands of languages out there.

02:55

But yet we are focusing on a handful of them.

02:58

But it does have most of the mainstream languages we program in.

03:02

Are tilted towards one way or one style of programming.

03:06

Which is nerve wrecking because we could go through an entire career in programming.

03:10

These mainstream languages are not even get an opportunity to realize a whole new different world that's out there.

03:17

What one such thing is what's called applicative order versus normal order.

03:22

It's really funny in our field how we name things.

03:25

It turns out normal order is actually quite abnormal.

03:28

We don't use it as too often.

03:30

But what does it really mean?

03:31

Let's take a look at one example here for a minute.

03:34

Here is a little Java code.

03:36

And in the Java code I'm going to go ahead and call a function flu.

03:39

And I'm going to call another function let's say add over here.

03:43

Now I'm going to pass one and two.

03:45

We clearly know how Java works in this case.

03:48

It's going to call add and then it's going to call the function flu.

03:51

But it doesn't have to be that way.

03:53

And that order of execution is called the applicative order.

03:56

The word applicative really means in the order in which we apply it.

04:00

But the normal order actually does things pretty different.

04:03

Let's take a look at what that really means with a little example.

04:06

I'm going to write a very small example here in Haskell.

04:09

I'm going to say add a b equal to a plus b.

04:12

So it's a fairly simple function.

04:14

It's pretty self explanatory what this function is doing.

04:17

I'm just adding two values right here.

04:19

Then I'm going to call evaluate and pass a value to it as a parameter.

04:24

And all that the evaluate function is returning is the value back to us.

04:28

Now I'm going to call a print function.

04:30

I'm going to call the print function.

04:32

I'm going to call print right here.

04:34

I'm going to call evaluate and call add one and three.

04:37

One and two here.

04:38

I'm going to execute this little code.

04:40

And it produces a value of three.

04:42

However, how does Haskell really work?

04:45

In the case of Haskell, Haskell you go to Haskell and say Haskell call add.

04:50

And Haskell would say, but why?

04:53

Well, because I want to pass the result of that to evaluate,

04:56

then Haskell says, then go call evaluate.

04:59

Why do you bother me?

05:00

Well, OK Haskell call evaluate.

05:02

Like why?

05:03

Because I want to call print.

05:05

Well, then go call print.

05:06

Why are you bothering with the evaluate?

05:08

Well, I'm going to prove this.

05:09

But how do we prove it?

05:11

And unfortunately, in Haskell haskell being a functional programming language,

05:15

you cannot just drop impurity anywhere you want to.

05:18

So if I were to go here and put a print statement,

05:21

Haskell will yell at me and say, what are you trying to do in a pure function?

05:25

So I was kind of sitting and scratching my head.

05:27

How do I prove the obvious here?

05:30

And I never thought I would use a debugger to prove anything in my life like that.

05:34

So I'm going to just do exactly that right here.

05:37

So I'm going to bring up GSEI, which is the Haskell Ripple.

05:41

I'm going to load up right here.

05:43

The sample dot h is the file I just wrote right now.

05:47

I'm going to put a break point on line number one, character number 16.

05:52

And the break point is right there.

05:54

I'm going to call the main function.

05:56

And I'm showing you the obvious right here.

05:58

It is waiting as you can see on line number one.

06:01

And it is waiting at the break point.

06:03

Now, of course, I'm going to say continue if you will.

06:06

So I'm going to go ahead and type continue.

06:09

And as I type continue, you can see that it is actually displaying the result of three.

06:14

Approved that it actually called the add function because it was stopping on line number one.

06:20

Well, of course, I took all this effort to show you the obvious, which is kind of pointless, isn't it?

06:25

But let's get back to this code for a minute.

06:28

I'm going to go back to the evaluate function.

06:31

And I'm going to return the value of 42 right here.

06:34

What I run the coded printed 42.

06:36

But this time, I'm going to go back to Haskell and say call add and it says why.

06:41

Well, I want to call evaluate.

06:43

Then call call evaluate.

06:44

When it turns out Haskell never actually calls the add function in this case.

06:49

How do I know? Let's prove this again.

06:52

Let's go back to the command prompt.

06:54

Let's open up the Rappel one more time.

06:56

Let's load up the program again.

06:58

Let's set the break point one more time.

07:00

Now that the break point is set, I call the main function.

07:03

And notice it never bothered to break on line number one.

07:07

That's approved that it never actually bothered to stop on the add function.

07:12

So what are we really proving with this little example?

07:15

Well, that is a normal order of execution that you're seeing right there.

07:19

And it turns out that most languages we use in the main stream use applicative order.

07:25

But normal order is rather uncommon and abnormal in a way.

07:29

And a lot of languages don't use it.

07:31

But one language that does that is, of course, Haskell.

07:34

You saw that really doing it.

07:36

Well, it turns out that some languages are born lazy.

07:40

They are born by the beach and they just sit there and have a good time.

07:44

But some languages have to work really hard to be lazy.

07:48

They're kind of like me.

07:49

I'm always agitated.

07:50

I'm always up to something.

07:51

And my wife says, why do you relax?

07:53

I'm like, how do you do that?

07:54

And that's the way we are like, you know, some languages are absolutely eager.

07:58

They're not really lazy.

08:00

But it turns out that lazy evaluation is absolutely critical.

08:04

So what is the benefit of laziness?

08:06

The benefit of laziness is really efficiency.

08:09

So if you want to really make your program efficient,

08:12

efficiency is not running things faster,

08:15

but by avoiding things that shouldn't be done in the first place.

08:19

So imagine taking the chunk of computation and not running them

08:23

because you don't really need the results of it,

08:26

this can become really powerful.

08:28

Like what?

08:29

Imagine this for a minute about postponing evaluation.

08:32

On January the second, the boss calls you into the office.

08:36

And the boss tells you, one January the second,

08:39

that you're going to work on an important project,

08:42

and the result, the report of it is due on April the 15.

08:46

What do you do?

08:47

You come out of the boss's office on January the second,

08:50

go to your desk and start on this right away, correct?

08:53

Of course not.

08:54

You will start on it promptly on April the 14,

08:58

because it's you on the 15th, isn't it?

09:00

What is that call being smart?

09:02

And that's what you would do.

09:03

I remember the time when I was in school.

09:05

I was really a terrible student.

09:07

And I would see all these students working really hard for the exam

09:11

for months away.

09:12

And I would always look at them and say,

09:13

what are you doing, preparing so hard for the exam?

09:16

Because you see there's a lot of things can happen

09:19

between now and the exam.

09:21

On the exam day, potentially there could be a really heavy snowstorm

09:24

or a thunderstorm and the whole school could be cancelled.

09:27

The professor may die before the exam.

09:30

There's a lot of things that can happen, isn't it?

09:32

So what do you do as a very efficient student?

09:34

You wait until the night before the study.

09:37

Well, that's kind of like what I really like.

09:39

It's laziness leads to efficiency.

09:41

And just in time, we call it,

09:43

or we call it the last responsible moment

09:46

while all these things are really good things.

09:48

So how do we really achieve this?

09:50

Let's take a look at one example of this.

09:52

How to really be able to achieve something like this.

09:54

So in order to understand this,

09:56

let's take an example here in two different languages,

09:59

if you will.

10:00

I'm going to write a little example here in school.

10:02

I just do entering the thought.

10:04

Other languages do this as well.

10:06

Like, for example, grew, we cartlin.

10:08

You can do these things in multiple different languages.

10:10

Let's take a look at an example of this right here.

10:13

I'm going to define a function.

10:15

And the function I'm going to define here is called Compute.

10:17

And this takes a value integer.

10:19

And all I'm going to do within this particular function

10:22

is return n times to just, you know,

10:25

very trivial function.

10:26

But good enough for us to start with.

10:28

So that is my compute function ever

10:30

here in in a column.

10:32

But here on the Java side,

10:34

let me go ahead and write the same function here.

10:37

I'm going to say Compute where I'm going to take a number.

10:40

And all I'm going to do is simply return number times 2.

10:43

So pretty much about the same code in both languages.

10:46

But on the scale side, what I'm going to do is say x is equal to,

10:51

let's say 4.

10:53

And I'm going to say, in this case,

10:55

similarly on the Java side, I'll say,

10:57

a final x is equal to 4.

10:59

But I'm going to simply say, if on the other hand on the other side,

11:04

I'm going to say, if x is greater than 5,

11:08

and the compute, let's call the compute function.

11:11

And I'm going to say compute of,

11:13

let's say, about x is greater than 7,

11:16

then I want to print out,

11:18

let's go ahead and say result 1.

11:20

Otherwise, I'm going to say result,

11:22

and I'm going to print out, let's say result 2.

11:24

I want to do something very similar to this on the side of Java as well.

11:28

So let's go ahead and write the before we try to execute this.

11:31

So I'm going to say, if x is greater than 5,

11:33

and compute of, let's say x is greater than 7,

11:37

I want to simply output result 1.

11:39

Otherwise, I'll simply output over here.

11:42

Let's go ahead and say result 2.

11:44

So these two are pretty much similar functions between Scala and Java here,

11:48

as you can see.

11:49

But I'm going to execute this little code.

11:52

And my question really at this point is,

11:55

will the compute function be called?

11:58

What do you think?

11:59

No, I see people saying no over there.

12:02

Well, it will not be called,

12:04

and let's verify that it's actually not being called.

12:06

So when I go back and run this code,

12:08

what does the output say?

12:09

It says result 2, and clearly compute was not called.

12:13

But I'm going to ask the question,

12:14

why was compute not called?

12:16

Anyone recognizes the reason for it?

12:19

Come on, don't be shy.

12:21

Yeah, that's why charts are queuding, isn't it?

12:23

So we know this is a charts are queued feature,

12:26

and guess who, let's go ahead and say called over here,

12:30

guess who introduced that feature?

12:32

Well, it turns out charts are queuding,

12:35

has been in languages for a very long time.

12:38

John McCarthy introduced charts are queuding,

12:40

as part of list programming,

12:42

and languages have ever since used this.

12:45

It's a folklore, isn't it?

12:46

Everybody knows about charts are queuding.

12:48

We all come to expect it.

12:50

On the other hand, I'm going to go back to this code

12:53

and say a temp over here,

12:56

and I'm going to then say,

12:58

valve temp is equal to compute of x.

13:01

Now I save the variable into a temporary variable,

13:05

and then I'm going to pass and use that variable.

13:08

Similarly, I'm going to say over here,

13:10

a temp is equal to,

13:12

let's say, compute of x,

13:14

and I'm going to change this to a temp over here.

13:17

And back to the scholar code,

13:19

my question is, will compute be called now?

13:23

What do you think?

13:25

A little question mark on people's face,

13:27

not sure.

13:28

Let me change the question.

13:30

Should compute be called now?

13:32

Yeah, that's a no, right?

13:34

We shouldn't call compute,

13:35

and yet when you run the code,

13:37

compute is actually called.

13:39

How sad that is, isn't it?

13:41

Now, why is compute really called?

13:43

Well, the reason compute is called,

13:45

is, hey, what if there is a side effect?

13:48

You say, wait a second,

13:49

you're talking about side effects suddenly,

13:51

but a minute ago,

13:53

you were having exactly the same compute method,

13:56

you had it in the short circuit situation,

13:58

and even if there was a side effect,

14:01

why in the world did you not call it?

14:03

Well, the short answer to that question

14:05

is language specification.

14:07

You can never argue with language specifications.

14:10

The language specification says,

14:12

even in the event of a side effect,

14:15

if you're in a short circuit situation,

14:17

we have the right not to call the function.

14:20

On the other hand, in a regular conditional statement,

14:23

the language says, oh, my gosh,

14:25

what if really we are going to have a side effect,

14:28

I better call it,

14:30

so as a result,

14:31

as you can see in the case of scholar,

14:33

and in the case of Java,

14:34

it ended up calling the function.

14:36

But I know you all said,

14:38

it shouldn't be called,

14:39

I totally agree with it,

14:41

so what you can do is you can say lazy right there,

14:44

and by saying lazy,

14:46

you can see that scholar is no longer calling the function,

14:49

because it determines that it is not really needed.

14:52

Without the word lazy,

14:54

you can see that it's actually calling the function,

14:56

but when I drop the word lazy in there,

14:59

you can see it's no longer calling it.

15:01

But just to illustrate this,

15:03

if the value of x was 14,

15:05

you can see that it is calling the function,

15:07

but if the value of x is 4,

15:09

it is no longer calling the function.

15:11

So by marking it lazy,

15:13

you're able to achieve that in the case of scholar.

15:16

Likewise in the case of Java,

15:18

I'm going to go ahead and say lazy right there,

15:21

and when I run the code,

15:22

it doesn't work.

15:23

I know for a minute you were like,

15:25

gosh, this is awesome, isn't it?

15:26

Sorry I disappointed you,

15:28

so no it doesn't work.

15:30

Well, but you know,

15:31

you say like, but I want it,

15:32

I why can't I have this particular feature?

15:35

And so the answer to that question is,

15:37

yes, you can have it,

15:39

but how can you introduce laziness on your own?

15:42

And that is one of the questions to really think about.

15:45

And for this, I want to step back a minute

15:47

and talk about one statement,

15:49

and I would argue,

15:50

this is probably the most profound statement ever in our field.

15:56

There's not a single day that I sit and programming

16:00

when I don't pause and appreciate this particular statement.

16:04

I don't think there's anything more profound in our field,

16:06

and this was said by a gentleman named David Wheeler,

16:09

and David Wheeler probably said,

16:11

the most wisest thing ever.

16:13

And he said, all problems in computer science

16:17

can be solved using one more level of interaction.

16:23

And this to me is the most phenomenal statement ever.

16:28

Now if you really think about it,

16:30

level of interaction is the master design

16:34

of all designs in my opinion.

16:37

Because this is the master as and fundamentally

16:40

skillful way of doing things,

16:43

and this is the most phenomenal mastery of design

16:46

if you think about it.

16:48

Because a level of interaction simply says,

16:50

rather than solving this here,

16:52

solve a problem that in turn will solve the problem.

16:55

We use this a lot in computer programming.

16:58

In C programming languages,

17:00

we use pointers as level of interaction, for example.

17:03

Well, it turns out in functional programming,

17:06

the level of interaction is there too.

17:08

The level of interaction in functional programming

17:12

functional programming comes from,

17:16

well, where does it actually come from?

17:18

Well, if this is one of my realization call me silly,

17:21

but I get excited about these things when I program

17:24

is when you could be programming for several years,

17:27

and one day suddenly something really dawns on you

17:30

that maybe it's obvious to everybody around you,

17:33

but you realize like, whoa, this is really awesome.

17:36

And to me, that is in level of interaction

17:38

functional programming comes from a lambda expressions.

17:41

So this to me is a,

17:43

a moment because lambda's give you that level of interaction.

17:47

So what does a lambda say?

17:49

A lambda says, rather than calling this function now,

17:52

call this anonymous function,

17:55

which is a lambda expression,

17:57

which in turn can call this function at a later time.

18:00

So to me, this is one of the really critical aspects of

18:04

lambda's is that they give you the level of

18:07

interaction in functional programming.

18:09

And then once we look at it this way,

18:11

it changes the whole world for me because it's a design tool

18:15

that I can look at and appreciate now

18:18

when I program in functional style,

18:20

because it's something that changes the way that I perceive

18:23

and use the solution at this point.

18:25

So what I can do here in the code is,

18:28

I can now say here a lazy,

18:31

if you will, of integer,

18:33

and I'm going to then say 10,

18:35

and then I will say,

18:37

notice over here,

18:39

I'm going to say new lazy,

18:41

and look at this very carefully.

18:43

If I call the compute method right here,

18:46

this is a applicative order.

18:48

Java will immediately call this function

18:51

because that's what Java does.

18:53

It's an applicative order language.

18:55

But what I can tell Java is,

18:57

do me a favor,

18:58

don't call the compute now,

19:00

instead call it later.

19:02

This error is almost like a level of

19:05

interaction isn't it?

19:06

So it is saying,

19:08

don't execute compute now,

19:10

execute it a little later.

19:12

So this is the degree of postponing

19:14

the evaluation,

19:15

and you're saying,

19:16

not now a little later,

19:17

please,

19:18

and that little parenthesis

19:21

is an indication of a lambda postponing

19:24

evaluation of the compute method.

19:26

So what we could potentially do here

19:28

is we could create a class called lazy,

19:31

where the class lazy could hold onto

19:34

an instance,

19:35

if you will,

19:36

and it could also hold onto

19:38

a little supplier of P,

19:40

where the supplier comes from

19:42

the functional interface

19:44

in the case of Java,

19:45

and then I can,

19:46

of course,

19:47

the supplier will call it the supplier,

19:50

and then of course,

19:51

what I can do is create the lazy constructor,

19:54

which is taking the supplier,

19:56

and what I can do is simply take the supplier,

19:59

store it away a supplier equal to the supplier,

20:03

but then I can write a method called get,

20:06

where the method get can say,

20:09

if the instance is equal to now,

20:12

then of course,

20:13

I could say,

20:14

this is equal to the supplier.

20:16

Get the value,

20:18

get rid of the supplier at that point,

20:20

we don't really care about it anymore,

20:22

and then return the object

20:24

that is held within the object.

20:26

So you could start writing things,

20:27

of course,

20:28

I'm writing this code here,

20:29

but you could use it from third-party libraries,

20:31

if you want to,

20:32

or you can put it in a separate utility,

20:34

and reuse it in your own applications.

20:36

But writing this lazy evaluation,

20:39

I'm saying,

20:40

postponing this to a later time.

20:42

As a result,

20:43

I can come in here,

20:44

and get the value of them

20:46

when I really made it,

20:47

and ignore the warning just for a minute,

20:50

and you can see at the very bottom,

20:51

the result too,

20:52

is being displayed right in there.

20:54

On the other hand,

20:56

if I were to modify this to a 4p in,

20:58

you will notice at the very bottom,

21:00

it is called and result 1.

21:02

So the calling of that is postponed,

21:05

until you no longer can postpone it,

21:07

so you can have laziness built in

21:09

to your applications that way,

21:11

and that comes from the level of

21:13

indirection that I was talking about a minute ago.

21:16

So laziness comes with a lambdas in most of these languages,

21:20

and that gives us a level of indirection,

21:22

we can benefit from really nicely.

21:25

Well, this leads us to how we can actually benefit

21:28

from this kind of laziness in programming.

21:31

So to understand this,

21:33

let's talk about laziness in collections of objects.

21:37

This is a very critical aspect to think about,

21:39

because functional programming gives us elegance in code.

21:43

It gives us beautyiness in code,

21:45

but at the same time though,

21:47

we have to be very careful because we cannot really be happy

21:50

with elegance and beauty,

21:52

we really attended the day,

21:54

have to really look for performance as well.

21:57

So to understand this,

21:58

let's take a little example and play with it.

22:00

Let's say for a minute,

22:02

given a collection, let's say collection of numbers,

22:06

well, of some ordered collection of numbers,

22:09

we'll say given a ordered collection of numbers,

22:13

I'm going to say find the double of the first number,

22:18

greater than three, and this even.

22:21

So I want to find the first number that's greater than three,

22:24

and that is even.

22:26

How do I do this in the imperative style of programming?

22:29

Well, in the imperative style of programming,

22:31

we're all used to doing this a lot in our experience.

22:35

So I'm going to start with a list of integer,

22:38

we'll call it as numbers equal to,

22:40

and let's say list off,

22:42

and what am I going to provide for this particular list?

22:45

I'm going to say this is going to be my list of numbers,

22:48

let's say 1 to 10, but with a small difference.

22:51

I'm going to say 5 and 4 as a sequence of numbers.

22:55

So notice I have 1, 2, 3, 5, 4, 6, 7, 8, 9, and 10.

23:00

But how do I do this in the imperative style?

23:02

Well, in the imperative style of programming,

23:05

what we're going to do is to first of all say,

23:08

end to result is equal to 0.

23:10

And of course, at the very end, I want to output the result,

23:13

but what do I do here?

23:15

For end, I equal to 0, I less than number start,

23:20

and I'm going to think about what to call here.

23:22

Is it length, is it size, is it count?

23:25

We cannot have a standard in our industry,

23:27

because that would make life easy.

23:29

So in this case, of course, it's a size of its list.

23:32

It's a length of its an array.

23:35

It's a count of its a different language.

23:37

And then, of course, you have to make another choice.

23:39

Is it plus or I plus plus or plus plus I?

23:42

And then you pause for a second as the question,

23:45

is that less than or less than or equal to every single time you write it?

23:50

Somebody asked the other day, what is the symbol stand for?

23:53

I said, that's the international symbol for, I'm confused.

23:56

Because every time we have to pause and ask the question,

23:59

now, to be fair, of course, you don't have to struggle that hard anymore,

24:02

you could have said, given an element that comes from numbers,

24:07

and what am I going to do now?

24:09

I can simply say over here, if element is greater than 3,

24:14

and if element, more 2 is equal to 0, then, of course,

24:19

result plus equal to element time 2.

24:22

Now, as an observant reader, you probably look at this code and say,

24:26

you're wrong, you are forgetting to put a break right here.

24:30

Now, if you don't put a break in the best case,

24:33

you will get a poor performance in the worst case,

24:35

you will get a wrong result.

24:37

But it's your responsibility to do all of this in your code.

24:40

And notice when I run this code, it produces the result of 8.

24:44

But the problem with imperative style code as imperative style code

24:48

is very misleading.

24:50

In imperative style code, I'm going to say,

24:53

has a built-in accidental complexity.

24:58

So, what is complexity?

25:00

Accidental complexity comes from solution space.

25:04

Now, the solution is complex because you're reading this code

25:07

and trying to figure out if it's right,

25:09

and typically what happens in my case is,

25:11

I put this code out in a few days later,

25:14

you know who walks in my tester,

25:17

and my tester says, your code sucks.

25:20

And I always tell my tester, don't tell me my code sucks,

25:23

tell me how it sucks today,

25:25

because every day it seems to suck differently.

25:28

But the point really in this case is,

25:30

the tester says, well, I tried your code

25:34

with an empty collection of data,

25:38

and your result was zero when the results would be non-existent.

25:43

I tried your code with a collection of only numbers

25:47

that are odd numbers you gave a wrong result.

25:50

I tried with numbers less than three gave me wrong results.

25:53

It failed in so many ways.

25:55

Well, the reason it failed in so many ways is

25:58

the result of zero is rather invalid.

26:01

So, once the user at a tester tells me it's wrong,

26:04

what am I going to do now?

26:06

I'm going to go back to this code and say,

26:08

all right, I'll fix it.

26:09

I'm going to say, integer result is equal to now,

26:13

and then, of course, the question is,

26:15

how do you feel about this?

26:17

Now, of course, is a smell,

26:19

and this is not going to be very much fun to write the code.

26:22

It only goes worse at this point than it was before.

26:26

So, we struggle with all this and say,

26:28

gosh, there's gotta be a better way to write this code.

26:31

Well, it turns out there is actually a better way,

26:33

and that is the functional style code

26:36

has reduced complexity in general.

26:40

Well, of course, functional style code removes this

26:43

accidental complexity from our code,

26:46

and part of the reason is that the code

26:49

reads like the problem statement.

26:53

So, one of the real beauties of this is,

26:55

the code begins to read like the problem statement.

26:58

So, what I can do here is, I can say,

27:00

output, and at this point,

27:02

I'm going to say numbers.stream,

27:05

and there comes the stream,

27:07

which is an internal iterator.

27:09

So, I say numbers.stream,

27:11

a dot filter, and what I'm going to do here in this example is,

27:16

I'm going to start with the filter function.

27:18

So, give me a second.

27:19

I want to reward back to what we had a minute ago,

27:21

because I want to show a difference between those two as well.

27:24

So, in this case, of course,

27:26

what I'm going to show you here is,

27:28

that the functional style code has reduced complexity.

27:31

The code begins to read like the problem statement

27:34

as we saw here.

27:35

So, let's ignore that for a minute.

27:37

Let's go ahead and put an int right here.

27:38

But at this point, what I want to do really is,

27:41

talk about how the functional style code is less complex.

27:45

So, for that reason,

27:47

let's go ahead and leave that code out there for a second.

27:50

Let's go ahead and say,

27:51

output numbers.stream.

27:54

But this time, I'm going to say,

27:55

filter, given an element,

27:57

element is greater than three,

27:58

and filter again,

28:00

given an element,

28:01

element more two is equal to zero,

28:04

and then I'm going to say,

28:06

map to int.

28:08

Well, in this case,

28:09

I'm just a map,

28:10

and I'm going to say,

28:11

given an element element times two,

28:13

but I'll say,

28:14

find first at this point.

28:16

And if the value doesn't exist,

28:18

maybe give me a zero or whatever I want to choose,

28:21

instead of it,

28:22

I can definitely make that decision.

28:24

So, given this code,

28:25

when I run the code,

28:27

both the pieces of code give me exactly the same result,

28:30

the imperative and the functional style code.

28:33

But on the other hand,

28:34

the functional style code is a code

28:37

begins to read like the problem statement,

28:39

given a collection of numbers,

28:41

get me numbers that are greater than three,

28:43

get me the numbers that are even,

28:44

get me the double of that,

28:46

and then get me the first one,

28:48

and if not, you may as zero.

28:50

Well, if you look at this code,

28:51

this code is elegant.

28:53

This code is,

28:54

I'm going to simply say,

28:56

this code is cute,

28:58

and we can absolutely agree with that,

29:00

and we can say this code is cute.

29:03

But unfortunately, though,

29:05

a lot of languages give you this.

29:07

Java does this,

29:08

C-sharp does this,

29:10

but Ruby and Python and small talk and,

29:14

and, and,

29:15

Ruby and JavaScript,

29:17

a lot of languages give this.

29:19

But I've come to a grim realization in life,

29:22

and that is,

29:23

a cuteness is not sustainable.

29:26

And this is the sad part,

29:28

when I want to go to see a very small child,

29:31

a friend, a relative call,

29:32

see one says,

29:33

we have a baby,

29:34

and we go to visit the baby.

29:35

This is just so small baby.

29:37

And of course, when you go to see the baby,

29:38

the first thing my wife wants to say is,

29:40

how cute,

29:41

and I go to the child and say,

29:43

kid, it's not going to sustain.

29:45

And this is the truth, isn't it?

29:47

Because the child is so cute

29:49

for two years of the human life.

29:51

And then if two years,

29:52

what do we say?

29:53

You're annoying.

29:54

You speak too much.

29:55

And that's called the terrible two.

29:57

So, cuteness is not sustainable,

29:59

unfortunately.

30:00

And that is exactly true,

30:01

what for functional style code.

30:03

You cannot look at this code and say,

30:04

it's cute.

30:05

And the next thing somebody sells to you is,

30:07

yeah, alright.

30:08

What's the performance look like?

30:10

Well, if you cannot give performance,

30:12

all the cuteness is a total waste in our life.

30:15

So, we want to be cute,

30:17

but we can,

30:18

but we want to give performance as well,

30:20

that's absolutely critical.

30:22

So, in other words,

30:23

efficiency,

30:25

efficiency rules at the end of their day.

30:28

Right?

30:29

So, this is the true fact of life,

30:31

efficiency rules at the end of their day.

30:34

So, you cannot just simply say,

30:36

it's cute and walk away,

30:37

what about performance that becomes absolutely critical.

30:40

So, what do we do about efficiency of this code?

30:43

What if I look at line number 26 and say,

30:46

I compute the result for every single value,

30:49

and then for even numbers,

30:51

and then double those values,

30:53

and then I return the first throwing away

30:55

all the other computation,

30:57

what a real waste.

30:59

Now, let's think about what's going to happen

31:01

in this particular case.

31:02

So, going back to this code,

31:03

let's refactor this just a little bit.

31:05

I'm going to write a function here called Boolean,

31:09

and the Boolean is going to say,

31:11

E is greater than 3,

31:12

takes a number,

31:13

and it simply returns the number,

31:15

a greater than 3 for a minute.

31:17

Similarly,

31:18

I'm going to write two other functions.

31:20

The next function is going to be E's even,

31:23

and all that it's going to do is return

31:26

more 2 is equal to 0,

31:28

and finally,

31:29

this is going to be a double it,

31:31

and which is going to simply return the value

31:34

and times 2.

31:35

So, given this code,

31:37

of course,

31:38

what I want to do is use that code in here.

31:40

Now, look at the imperative style code

31:42

for just a minute.

31:43

How does the imperative style code work?

31:45

Just the highlighted part,

31:47

if you focus on.

31:48

We pass a 1,

31:49

it says,

31:50

1 is not greater than 3,

31:51

2 is not greater than 3,

31:53

3 is not greater than 3,

31:54

or 5 is greater than 3,

31:56

but it's not even,

31:57

but 4 is greater than 3,

31:59

and 4 is even,

32:00

double it.

32:01

So, that was eight computations

32:03

to get the result in the imperative style code.

32:06

Let's prove it.

32:07

So, to prove it,

32:08

I'm going to say,

32:09

E is greater than 3 right here,

32:11

and I'm going to then say,

32:12

E is even of N,

32:14

or our E rather here,

32:16

and then finally,

32:17

I'm going to simply call a double it over here,

32:20

and of course,

32:21

as a result,

32:23

we can pass the data.

32:24

When I run the code,

32:25

what is it going to do?

32:26

Well,

32:27

in this case,

32:28

of course,

32:29

it is going to provide that value.

32:31

Let's go ahead and make sure that I'm using the right function here.

32:33

So, when I go back and call this function,

32:35

you can see,

32:36

it is telling me that it is going to be eight computations

32:39

to run this code.

32:41

So, what is this really provide for us?

32:44

Let's go ahead and put that little statement right here.

32:46

I'll say,

32:47

call the E is greater than,

32:49

we'll say E is greater than 3,

32:51

and then we'll say,

32:52

called over here,

32:53

and we'll say,

32:54

E is even,

32:55

and finally,

32:56

called over here,

32:57

we'll say,

32:58

double it.

32:59

And when I run this code,

33:00

what is it called for?

33:02

Well,

33:03

we'll go ahead and say,

33:04

let's go ahead and say,

33:05

plus N here.

33:06

So, we can actually appreciate the value,

33:08

it's calling that for,

33:09

and then we'll simply stay plus N.

33:11

So, when I execute this code for the imperative style code,

33:14

you can see that it performed a total of eight computations right there,

33:18

1, 2, 3, 4, 5, 6, 7, 8.

33:21

So, eight units of work,

33:22

and we got the result in the imperative style of code.

33:25

But the question to ask is,

33:27

what about the functional style code?

33:29

Well,

33:30

if I'm taking 10 values and comparing greater than on 10,

33:33

that is 10 computations.

33:35

That is,

33:36

that is,

33:37

on a rival,

33:38

isn't it?

33:39

10 is greater than 8.

33:40

Let's add,

33:41

instead, to injury,

33:42

this is going to compare the even for seven values in the collection.

33:47

This is going to double four values,

33:49

and then it's going to return the first value.

33:51

So, that is going to be 10 plus seven is 17 plus four,

33:54

is 21 computations.

33:56

So, what if I say,

33:58

the functional style is cute,

34:00

but you're going to spend 21 computations versus eight,

34:04

you're going to say,

34:05

get out of here.

34:06

So, we are not going to be tolerating a functional style code,

34:09

if it results in poor performance.

34:11

So, what do we do about it?

34:13

Well, thankfully,

34:15

this is one of the things that streams really provide very elegantly.

34:19

So, what does the stream really do?

34:22

Streams are really built on top of laziness.

34:26

So, what does it really mean that streams are really lazy?

34:30

Well, to understand this,

34:32

let's go ahead and convert this code real quick,

34:34

and we will go ahead and call the ease even right here,

34:37

and then finally,

34:38

of course, we'll go ahead and call the double it function right here as well.

34:42

But before we run this,

34:44

let's talk about how this is going to work.

34:46

Now, when you look at the stream,

34:48

the streams are fundamentally lazy.

34:51

I've only seen this characteristics between my own children

34:54

and streams.

34:55

My children are fundamentally lazy.

34:58

I'll share with you an experience I've seen in my house.

35:00

My wonderful wife will tell my son,

35:03

you know, a torn off the TV.

35:05

It's like no words were spoken.

35:08

And then she will tell him,

35:10

what the trash out and no muscles were really moved.

35:13

And then she tells him,

35:15

do your homework not a pencil was picked.

35:18

At this point, she simply says,

35:20

call daddy and everything works.

35:22

And so, they're going to rename this as call daddy.

35:25

So, the point, and somehow,

35:27

since it's called mommy,

35:28

it depends on the household,

35:29

I always say parents play a good cop in a backdrop role,

35:31

you cannot know what I play.

35:33

So, the point really is that these are called terminal functions.

35:37

The terminal functions are the ones

35:39

that trigger the evaluation.

35:41

So, the way that streams work is,

35:43

when you go to a stream and say filter,

35:45

it's like, yeah, maybe later.

35:47

Hey, filter again, maybe another time.

35:50

Map, well, some other time,

35:52

and find first, or dear, let's do it.

35:54

And at that point,

35:56

it's going to do it minimally, what's expected.

35:58

So, if I run this code,

36:00

notice that we have exactly the same sequence of evaluation,

36:04

eight calls to this function,

36:06

no more and no less in this particular case.

36:09

So, the functional style code is as efficient as

36:12

the imperative style code,

36:14

when it comes to the number of computations,

36:16

it performs, and laziness really brings us for that.

36:19

And without laziness,

36:21

there would be no fun using the

36:23

expressive nature of function of style of programming.

36:25

This is especially true with big data projects.

36:28

I work with clients who are dealing with literally

36:30

millions of data that they have to process,

36:33

and when we deal with 70 or 80 millions of data,

36:36

we cannot be doing inefficient computations,

36:39

laziness really saves the day for us,

36:41

and that becomes absolutely critical.

36:44

So, with that said, we have laziness,

36:46

but what is laziness really lead to?

36:49

So, to wrap this up, I want to really,

36:51

come back to this,

36:53

immutableity is essential for lazy evaluation.

36:59

This is absolutely true.

37:01

Immutableity is essential for lazy evaluation.

37:04

If you don't have immutableity,

37:06

if you're mutating data,

37:08

you cannot postpone evaluation.

37:10

You would always worried about

37:12

what's the value going to be now,

37:14

and if it is mutating,

37:16

your question is to use the value before mutation

37:19

or after mutation.

37:21

But if the value is immutable,

37:23

it doesn't matter.

37:24

It is not going to change.

37:26

You can evaluate now.

37:27

You can evaluate later,

37:28

or not bother evaluating at all,

37:30

and you can postpone that quite a bit.

37:33

Well, with that said,

37:34

lazy leads to two things.

37:37

One is efficiency.

37:39

But it also leads to one other beautiful thing,

37:42

which is infinite, infinite streams.

37:45

So, infinite streams are pretty darn good way

37:49

to express certain ideas in code.

37:51

It leads to efficiency,

37:53

but it also leads to infinite streams.

37:55

The idea of infinite stream is to be able to

37:58

generate a boundless collection of data,

38:01

but how in the world can we create boundless collection of data?

38:05

We can enjoy these ideas

38:07

if we get a good hang of laziness.

38:09

So, to understand this,

38:11

let's take a look at a slightly different example here,

38:13

let's go ahead and say that I want to start with

38:15

a little example of a sample,

38:17

where I have a method called esprime.

38:19

It returns whether a number is prime or not.

38:22

But notice the main function.

38:24

The main function says,

38:26

n is equal to 101 and n equal to 51.

38:29

It calls a compute,

38:30

but what does the compute do?

38:32

Compute is going to return the total of square root

38:35

of the first k prime number of starting with n.

38:37

That's a simple problem.

38:39

Let's try to implement it in the imperative style first.

38:42

So, I want to say double result is equal to zero,

38:46

and I want to return the result when I'm done with it.

38:49

But then what I'm going to do within this is,

38:51

I'm going to say over here,

38:54

what is this index is equal to zero,

38:57

or rather,

38:58

into equal to n,

39:00

in count is equal to zero.

39:02

Well,

39:03

if you notice over here,

39:04

we set up some variables,

39:06

but then I say,

39:07

while count is less than k,

39:09

and I come to a grinding halt

39:11

and ask the question,

39:12

is it less than k or less than

39:14

or equal to k?

39:15

Not sure,

39:16

still.

39:17

Then I say if,

39:18

and I'm going to take the index value

39:20

and say,

39:21

e is prime of index,

39:23

then what am I going to do?

39:25

Then I'm going to say,

39:26

a result is plus equal to

39:29

math dot square root of index.

39:31

Now,

39:32

if they ask you if the code is correct,

39:34

you're going to say,

39:35

no,

39:36

it's not correct.

39:37

Why not?

39:38

You have to increment the index.

39:39

Well,

39:40

then you say you have to increment the count as well.

39:42

Then you tell me,

39:43

you have to increment the index inside,

39:45

but you have to increment the count,

39:47

or rather,

39:48

count inside and index outside.

39:50

How do you feel about code like that?

39:52

This is an example of accidental complexity.

39:55

Now,

39:56

if you write a code like this,

39:57

you are staring at it to find out what the code is doing.

40:00

And that faithful movement,

40:02

the business analyst comes to you and says,

40:04

hey, how's it going?

40:05

And your response normally is,

40:07

I'm trying to find out what the code is doing,

40:08

you shut up.

40:09

That's all we feel about it,

40:10

right?

40:11

We get irritated.

40:12

What if the code can be really expressive,

40:14

wouldn't that be really nice after all?

40:16

Well,

40:17

that code ran,

40:18

but let's try to do this in the functional style,

40:21

how do we really execute it?

40:23

Well,

40:24

what I'm going to do here is,

40:26

returnstream.eternrate,

40:28

and I'm going to take the value end to begin with,

40:32

given an element,

40:33

element plus one.

40:35

Stop right there and look at that code for a minute.

40:38

What in the world is this code doing?

40:40

This is an example of an infinite stream.

40:43

This stream says,

40:45

I will give you value n,

40:47

n plus one,

40:48

n plus two,

40:49

n plus three,

40:50

n plus five n plus six,

40:51

and keeps on going,

40:53

never to ever stop giving you that value.

40:56

I know what you're thinking,

40:57

you're thinking,

40:58

oh my goodness,

40:59

if the stream is really infinite,

41:01

where in the world will you store it on the cloud,

41:05

of course.

41:06

But the point really is,

41:07

that this stream is absolutely boundless.

41:10

Well,

41:11

the beauty of the stream is,

41:12

it is lazy evaluation.

41:14

It is smart enough to say,

41:16

I will give you infinite stream,

41:19

if you dare to ask for infinite stream.

41:21

Of course,

41:22

we don't ever ask for something infinite.

41:24

So this is on demand.

41:26

It's like all the movies and Netflix.

41:28

You only watch what you ask for,

41:30

not everything else that's there.

41:32

It almost feels like there's infinite number of them, isn't it?

41:35

That's the whole point is,

41:36

you're going to generate this on the fly on the demand,

41:39

and that is laziness right there.

41:42

But then what I can do here is,

41:44

I can say,

41:46

and the filter simply says,

41:48

a given a collection of numbers,

41:50

get me only the prime numbers,

41:52

not anything else.

41:54

So given all the numbers starting with n,

41:56

give me all the prime numbers that start with n,

41:59

then I say,

42:00

and I'm going to ask for met square root.

42:04

So given all the numbers that start with n,

42:06

give me all the prime numbers that start with n,

42:09

but give me the square root of all those numbers,

42:12

and you say dot limit k.

42:14

Well, is it k or less than k or less than k,

42:16

or less than k,

42:17

it's k damn it,

42:18

don't have to worry about it,

42:19

move on,

42:20

and then you can perform the sum operation on it,

42:23

very easily,

42:24

as you can see,

42:25

to get exactly the same result as the other one.

42:28

So you can see how the code becomes very highly expressive,

42:32

and that's an example of using an infinite stream,

42:35

to solve the problem.

42:36

You can,

42:37

there's a slew of problems,

42:39

we never really experienced in languages like Java,

42:42

because we never had the ability to so easily create an infinite collection.

42:47

But now that we have the ability to have a level of interaction,

42:51

the ability to really postpone computations,

42:54

we can benefit from solving problems

42:57

that were otherwise even hard to imagine,

43:00

and we can use laziness,

43:02

and we can use infinite streams to solve the problem.

43:05

So to me that ability to do really infinite streams,

43:08

is one of the charming capabilities of the language,

43:11

that gives us the ability to look at some algorithms,

43:14

and solve those algorithms in ways we probably never really imagined solving in the past.

43:20

So to summarize what we talked about here,

43:23

laziness really is important,

43:25

because I want to reiterate what we talked about.

43:28

Efficiency is not about running a fast.

43:32

It is about avoiding a task that should not be executed,

43:39

in the first place.

43:41

So in other words,

43:42

this is really the core of efficiency,

43:44

if you really think about it.

43:46

Efficiency is not about running fast.

43:49

It is about avoiding tasks that shouldn't be done in the first place.

43:53

So as you are formulating your ideas and algorithms,

43:56

if there are computations that can be saved away,

43:59

as an example,

44:01

one of the things that leads to also is,

44:05

ability to really postpone computations,

44:08

the point where maybe you never have to execute it.

44:11

And if you never have to execute it,

44:13

why?

44:14

Because your code says,

44:16

if I don't have a reason to run this,

44:18

I can completely discard this evaluation,

44:21

and I don't bother running it,

44:23

and that is a very powerful way of executing,

44:26

expressing code.

44:27

So it's not just the expressiveness of the code,

44:30

but the efficiency of the code will bring to you as well.

44:33

As an example,

44:34

let's go back to this code and look at it one more time.

44:36

If I were to go to this code where,

44:38

I am implementing this code as a laziness,

44:41

if you will,

44:42

what I want to do is the ability to postpone operations.

44:47

Now, the code can be very efficient

44:49

to the point where you can never be more efficient than

44:53

not executing a piece of code, isn't it?

44:56

Because if when a code is not even executed,

44:59

it takes the least amount of time than any other thing you can provide.

45:02

So going back to this example real quick,

45:05

if you will,

45:06

when I run this code,

45:07

you can see it called all that function right there.

45:10

On the other hand,

45:11

let's go ahead and remove this for just a second,

45:14

and I'm going to simply stop at the fine first right here,

45:18

and at the very end of this,

45:20

I'm going to simply say,

45:21

done.

45:22

When I execute this code right here,

45:24

you can see all that output and it's said,

45:26

done,

45:27

but the beauty of this is,

45:28

I'm going to simply go back to this code,

45:31

and I'm going to comment out just the last part in the code,

45:35

and I'm going to simply restart this code,

45:38

and you can see it said,

45:39

done,

45:40

it did not bother to really execute the ease even function,

45:44

or the ease greater than three,

45:46

or the double it,

45:47

and to me,

45:48

that is the ultimate efficiency you can get,

45:50

is that you can draw this pipeline of these,

45:53

this functions,

45:55

and but the function pipeline is not exercise until

45:59

you attach a terminal operation to the pipeline.

46:02

If you don't attach a terminal operation,

46:04

obviously then the execution doesn't really,

46:07

based its performance,

46:08

and efficiency is by avoiding all the tasks

46:11

that has no real benefit,

46:13

no real advantage,

46:15

and that is where the efficiency comes through.

46:17

So if you're interested in downloading the code,

46:19

examples,

46:20

you're most welcome to download from my website,

46:22

I'll be delighted to hear questions that you may have.

46:26

Thank you very much.

00:00

Einführung in die faule Auswertung

00:20

Bedeutung der Unveränderlichkeit

01:33

Funktionale Programmierung Erklärt

03:17

Anwendbare vs Normale Ordnung

08:06

Vorteile der faulen Auswertung

15:56

Interaktionsniveau in der Programmierung

17:36

Lambda-Ausdrücke und funktionale Programmierung

19:26

Lazy Evaluation in Java erstellen

21:31

Imperativer vs Funktionaler Stil

30:22

Leistung vs Eleganz im Code

32:31

Verstehen von Streams in der funktionalen Programmierung

35:35

Faulheit und Terminalfunktionen

37:46

Unendliche Streams Erklärung

43:20

Effizienz in der faulen Auswertung

01:44

Was ist der Kern von funktionaler Programmierung, wenn nicht Unveränderlichkeit?

03:06

Warum gehen gängige Sprachen nicht wirklich auf faules Evaluieren ein?

14:04

Wie unterscheiden sich Haskell und Java beim Funktionsaufruf?

14:44

Was passiert, wenn man in Scala die verzögerte Auswertung verwendet?

16:11

Was für eine tiefgründige Aussage in der Programmierung löst jedes Informatikproblem?

17:52

Wie bringen Lambda-Ausdrücke eine Ebene der Interaktion in den Code?

26:40

Wie hilft der funktionale Stil dabei, die Komplexität beim Programmieren zu reduzieren?

30:11

Warum ist es wichtig, Niedlichkeit und Leistung im Code auszubalancieren?

34:21

Wie nutzen Streams Faulheit, um die Effizienz bei der Berechnung zu steigern?

35:35

Welche Rolle spielen Terminalfunktionen bei der faulen Auswertung von Streams?

38:11

Wie nutzen unendliche Streams faul evaluierung, um mit grossen Datensätzen umzugehen?


Java (Programmiersprache)Scala (Programmiersprache)Software-EntwicklungAlgorithmusComputerwissenschaftenComputerprogrammierungStruktur der DatenUnveränderliches ObjektFunktion höherer OrdnungKomplexität der ProgrammierungSoftware-EntwicklungFunktionale ProgrammierungParadigma der Programmierung

Beschreibung

Der Fokus liegt auf lazy evaluation, einer Programmiertechnik, die die Berechnung von Werten bis zu dem Zeitpunkt hinauszögert, an dem sie benötigt werden. Dieser Ansatz kann die Leistung und das Ressourcenmanagement in der Softwareentwicklung verbessern. Die Diskussion hebt die Bedeutung von Unveränderlichkeit hervor und argumentiert, dass sie entscheidend ist, um die Konsistenz des Zustands zu wahren und Nebenwirkungen in Anwendungen zu vermeiden. Ausserdem kritisiert der Sprecher die gängige Erzählung, die funktionale Programmierung ausschliesslich mit Unveränderlichkeit und höherwertigen Funktionen gleichsetzt. Stattdessen wird der Kern der funktionalen Programmierung als funktionale Komposition präsentiert, die es Entwicklern ermöglicht, Code auf eine intuitivere Weise auszudrücken, indem der Fluss von Daten durch verschiedene Verarbeitungsstufen betont wird. Die Sitzung ermutigt die Teilnehmer, sich mit dem Material auseinanderzusetzen und die praktischen Auswirkungen dieser Konzepte in ihren eigenen Programmierpraktiken zu berücksichtigen.