00:00:00.000
ready for takeoff
00:00:17.279
I'm Keith Bennett thank you for being
00:00:18.720
here I'm going to talk about lambdas
00:00:20.460
Ruby
00:00:22.020
I'm a ruby not rail is developer
00:00:24.480
um I say that playfully I you know I
00:00:26.640
have nothing against rails but just my
00:00:28.619
career experience hasn't included very
00:00:30.720
much of it I do a lot more of command
00:00:34.320
line applications tools for testing and
00:00:37.380
networking
00:00:39.480
um and um
00:00:42.540
yeah so
00:00:44.820
Ruby not rails but uh maybe in the
00:00:47.399
future rails I don't know
00:00:49.500
I am not a functional programming expert
00:00:51.680
I've just dabbled a little bit in Elixir
00:00:54.840
enclosure and erlang a few years ago I
00:00:57.239
just did some superficial study and
00:00:59.879
really liked it and and tried to bring
00:01:02.039
some of the concepts to my Ruby
00:01:03.660
programming
00:01:06.600
we'll be talking about
00:01:08.220
lambdas obviously what is the Lambda
00:01:10.380
what does it look like what is it good
00:01:12.479
for and how is it used
00:01:16.320
a Lambda is a free-floating function
00:01:19.200
it's not a part of a it's not an
00:01:22.200
instance of a well it's an essence of
00:01:24.119
the length of a proc class but it's it's
00:01:25.860
not really
00:01:27.840
um attached to an object
00:01:30.960
do you remember when you encountered
00:01:32.220
code blocks for the first time
00:01:35.400
do you remember how they were confusing
00:01:36.960
at first
00:01:38.520
if if they weren't confusing then you're
00:01:40.619
smarter than I am because for me they
00:01:42.180
were confusing I was wondering like
00:01:43.320
where does this how does this work but
00:01:45.900
we persevered and we mastered them
00:01:48.900
was it worth the effort
00:01:50.939
of course
00:01:52.860
lambdas are the next step in that
00:01:54.600
progression they're unfamiliar to many
00:01:56.520
of us but mastering them will bring a
00:01:58.979
lot of benefits
00:02:02.220
such as these
00:02:05.399
let's look at the ways to call a Lambda
00:02:07.500
first let's define one
00:02:09.899
can you see my cursor here yes great
00:02:12.060
that's working
00:02:13.860
um so here's a Lambda that takes a
00:02:16.680
single parameter and returns whether or
00:02:18.780
not it's a multiple of two
00:02:20.760
therefore whether or not it's even
00:02:22.920
and we're assigning it to a local
00:02:24.540
variable called is even now
00:02:26.760
unfortunately you can't
00:02:28.860
uh and a local variable name with a
00:02:31.140
question mark that would be nice but you
00:02:32.580
can't so that's
00:02:34.500
a terrible thing that you lose when you
00:02:36.060
use lambdas in local variables
00:02:39.660
um of course the conventional notation
00:02:41.940
is to use the call method by name
00:02:45.360
but there's also an abbreviated notation
00:02:47.580
without parentheses
00:02:51.540
you can also strangely call Lambda by
00:02:54.300
using square brackets but please don't
00:02:56.940
do this because well most of us see
00:02:59.459
square brackets we think there's a
00:03:01.260
collection that we're trying to find
00:03:02.519
something in
00:03:04.739
of course if you're in a community where
00:03:06.480
everybody's doing it and everybody
00:03:07.319
understands it it's a convention then
00:03:09.060
that's fine but usually that's not the
00:03:10.800
case
00:03:12.599
the Casey quality operator the triple
00:03:14.700
equals will also call a Lambda
00:03:17.400
but this too is confusing and I don't
00:03:20.159
recommend it
00:03:22.200
however in a case statement it can be
00:03:24.239
handy
00:03:25.200
if you specify a Lambda in a case
00:03:27.599
statement in the when Clause then that
00:03:30.659
Lambda will be called with the case
00:03:32.159
variable as a parameter
00:03:37.920
a lot of times I'm going to be talking
00:03:39.420
about lambdas and procs but a lot of
00:03:41.940
times it really doesn't matter whether
00:03:44.159
the object in question is a Lambda or
00:03:47.519
anything containing a call method
00:03:50.159
and the best name that I can come up for
00:03:52.860
this broader category is callable
00:03:55.440
anything with a call method
00:03:58.980
including all proc instances lambdas and
00:04:01.440
non-landas
00:04:04.080
modules are classes with a call class
00:04:06.840
method
00:04:07.980
instances of classes having a call
00:04:10.019
instance method
00:04:11.939
and any other object having a call
00:04:13.560
method added to it directly
00:04:17.160
here's an example of a method that you
00:04:18.900
could use to test whether or not
00:04:19.979
something is a callable it simply calls
00:04:21.660
respond to passing it call
00:04:24.020
we create a class with a call class
00:04:27.419
method a class with a call instance
00:04:29.520
method and when we call callable on all
00:04:33.300
these four they all return true so
00:04:34.860
here's just an empty Lambda an empty non
00:04:36.960
Lambda proc a class with a class method
00:04:39.660
call and an instance whose class has an
00:04:43.620
instance method call they're all true so
00:04:46.199
they're all interchangeable when you
00:04:47.520
have a method that's taking a callable
00:04:49.199
and
00:04:50.100
it doesn't have to be a Lambda it can be
00:04:51.900
anything with a call method because of
00:04:53.280
Ruby stuck typing unlike pretty much
00:04:55.139
every other language I think
00:04:58.800
and as a result the dot parenthesis
00:05:00.840
notation can be used for any of these
00:05:02.580
callables not just procs or lambdas
00:05:07.380
if you want to use a Lambda where a code
00:05:08.880
block is expected you just precede it
00:05:10.800
with an ampersand here
00:05:13.919
if you want to use a method where a
00:05:15.600
Lambda is expected you can do this
00:05:22.020
in Ruby versions before 1.9 this was the
00:05:25.199
only way to specify a Lambda
00:05:27.900
notice it's it's really the same as a
00:05:30.840
code block
00:05:32.100
and starting in one night we had the
00:05:34.500
stabby Lambda notation added which we
00:05:36.840
can use this way
00:05:40.320
if there are parameters to the Lambda
00:05:43.440
then this is the way to pass them in the
00:05:45.479
old notation which is the same notation
00:05:49.440
as with code blocks
00:05:51.060
and with a stabby Lambda it's the same
00:05:52.979
notation as method calls
00:05:57.620
self-invoking Anonymous functions it's a
00:05:59.940
fancy name for something that calls
00:06:02.039
itself and is not named um
00:06:04.740
we have three lines of code here and we
00:06:06.720
have them enclosed in a Lambda why would
00:06:09.120
we want to do that isn't that silly why
00:06:10.680
don't we just use those three lines
00:06:11.880
without the Lambda well once in a while
00:06:14.039
it comes in handy for hiding the
00:06:16.680
variable names the local variables from
00:06:18.720
the outer scope
00:06:20.280
and when I work with coffeescript a few
00:06:23.100
years ago they recommended doing this
00:06:24.780
for that very reason
00:06:28.259
the dot parents notation is a little bit
00:06:31.440
interesting in that you really need to
00:06:33.900
use it
00:06:35.100
um
00:06:37.259
um you can't just like with method calls
00:06:39.120
and Ruby normally you don't need
00:06:40.199
parentheses but if you're using the dot
00:06:42.120
parent notation you do here we create a
00:06:44.819
Lambda here we try to execute it but
00:06:48.060
IR Regis Returns the object itself the
00:06:50.160
Lambda object itself
00:06:52.380
and of course if if you use the
00:06:54.479
conventional method name you don't need
00:06:56.100
the parentheses
00:07:00.539
one of the things that's it's kind of
00:07:02.759
confusing the the proc class capital P
00:07:05.100
Roc class
00:07:07.699
can produce instances that are lambdas
00:07:10.440
and instances that are not lambdas
00:07:13.199
and the naming is unfortunate because
00:07:16.340
the name of the class proc is the same
00:07:19.979
as the name of the non-lander proc when
00:07:22.440
we Define it using this
00:07:25.740
so in spoken language if somebody says
00:07:28.500
proc it's really ambiguous
00:07:31.259
and so for that reason I usually use the
00:07:33.900
term non Lambda proc when I mean an
00:07:36.479
instance of the proc class which is not
00:07:38.639
a Lambda
00:07:39.960
and so here we have a Lambda we asked
00:07:42.240
for its class it's proc we ask are you a
00:07:44.460
Lambda this is a method on the proc
00:07:46.319
class and this is Method it says yes
00:07:49.139
here's a proc are you what is your class
00:07:51.900
proc are you a Lambda no
00:07:56.280
let's compare the behavior of lambdas
00:07:59.039
and non-lander procs the return behavior
00:08:01.919
is different a lambda's return returns
00:08:04.500
only from the Lambda and not from the
00:08:06.240
enclosing method or Lambda
00:08:09.060
as an example we have a method Foo we
00:08:11.520
have a Lambda and we execute it right
00:08:13.979
there in place
00:08:15.660
are we going to see this what will be
00:08:18.060
returned from well
00:08:19.800
turns out we do see this so This Lambda
00:08:22.680
returned from itself but not from the
00:08:24.300
foo method
00:08:26.039
in contrast a non-lander proc
00:08:29.099
return returns from its enclosing scope
00:08:31.500
if we do the same thing but with a proc
00:08:33.240
instead of a Lambda we don't see that
00:08:35.279
still in Foo because it has returned
00:08:37.800
from the method
00:08:42.120
already checking
00:08:43.740
uh in case you're not familiar with the
00:08:45.300
term arity it's just a number of
00:08:46.920
parameters passed to a method
00:08:49.200
checking is making sure that the correct
00:08:51.060
number has been passed
00:08:53.100
lambdas have strict arity checking
00:08:55.200
blocks and non-lamba procs do not
00:08:58.680
here's a Lambda that's expecting two
00:09:00.600
arguments if we call it with one we get
00:09:03.180
an error
00:09:04.680
in contrast
00:09:06.300
if we have a proc there's no complaint
00:09:10.440
and if we have a code block
00:09:13.380
then there's also no complaint so if we
00:09:15.899
hit Define this method here which
00:09:18.120
creates two random Point values and
00:09:20.279
passes them to the pass block
00:09:23.760
um if the block that is passed is only
00:09:26.760
expecting one parameter there's no
00:09:28.200
complaint
00:09:29.100
it just uses the first value and
00:09:31.320
substitutes anything else nil for
00:09:33.180
anything else that's missing
00:09:35.540
if we pass to the right number of course
00:09:37.740
it works correctly if we pass it too
00:09:39.480
many it still works correctly but it
00:09:42.420
uses nil for anything missing
00:09:47.279
so oh I just want to say before I go on
00:09:49.860
to that
00:09:51.240
um well I'll wait for that I have
00:09:52.920
another slide lambdas and procs are
00:09:54.959
selfless
00:09:56.700
um if you say puts self you won't get
00:09:59.279
the proc instance that the Lambda is
00:10:01.459
you'll get whatever it happens to be in
00:10:05.459
um and in IRB the name of the enclosing
00:10:07.800
object is main so that's why we see that
00:10:10.260
there same thing with non-lander procs
00:10:14.820
so because of these things
00:10:20.399
because of the differences in behavior
00:10:22.380
of arity checking and return Behavior I
00:10:25.440
believe that lambdas are preferable
00:10:26.640
they're safer they're more restrictive
00:10:28.880
now of course of course if if you need
00:10:31.920
that looser Behavior that's fine but
00:10:34.860
I think we probably rarely do need that
00:10:37.260
behavior
00:10:39.839
unnecessary complexity is our enemy
00:10:42.120
right you don't want a co-worker who's
00:10:43.800
going to make something overly complex
00:10:45.120
because it's going to be harder to
00:10:46.260
understand modify Etc
00:10:48.600
as software developers we strive to
00:10:50.459
maximize the ratio of functionality over
00:10:52.380
complexity we want to maximize the
00:10:54.540
functionality we give our users we want
00:10:56.700
to minimize the complexity that
00:10:59.100
with which we will need to deal as time
00:11:01.320
goes on with this software
00:11:04.620
why do we use local variables to limit
00:11:07.200
their scope why does it improve
00:11:09.420
Simplicity reliability readability
00:11:13.500
yes
00:11:15.779
regarding the number of instance methods
00:11:17.640
in a class you may have encountered a
00:11:19.200
situation where there is just a really
00:11:20.579
large number of instance methods in a
00:11:22.079
class
00:11:23.399
one metric of that complexity is the
00:11:27.060
number of possible Paths of interaction
00:11:29.820
and it turns out there's a formula to
00:11:31.320
calculate that it's the number of
00:11:32.760
methods times the quantity that number
00:11:34.620
minus one
00:11:35.820
so this is a very small class but
00:11:39.779
imagine in your head that it were larger
00:11:41.220
with only five methods we have a
00:11:42.959
complexity value of 20.
00:11:47.160
in my experience it's very often that a
00:11:49.680
method is used by only one other method
00:11:52.980
so let's say as an example two of these
00:11:55.019
methods are used by only one one of them
00:11:58.440
if we could find a way to move those two
00:12:00.420
into that method
00:12:02.880
look at the difference in the complexity
00:12:04.500
metric it's less than a third
00:12:07.079
so of course there'd be a tiny bit of
00:12:09.000
complexity in the in the right side
00:12:10.320
triangle but very little
00:12:12.839
so let's see if there's a way we could
00:12:14.579
do that well it turns out that in Ruby
00:12:16.860
you can Define methods within other
00:12:18.540
methods
00:12:20.519
we have a class C here we have an outer
00:12:22.680
method we just output a message and then
00:12:24.839
we Define another method
00:12:27.779
so we create an instance of that class
00:12:29.399
we call outer fine it's defining the
00:12:31.980
method it says it is
00:12:34.680
so how would you call the inner method
00:12:36.720
of a method well my best guess is that
00:12:38.820
it would be outer dot enter so let's try
00:12:41.160
that
00:12:43.200
doesn't work what's going on
00:12:46.740
well it turns out
00:12:48.420
that inner is just a regular instance
00:12:51.000
method like any other instance method
00:12:53.459
so we can't use methods as inner methods
00:12:56.100
in Ruby we cannot
00:12:58.800
but guess what we can use instead
00:13:01.500
lambdas
00:13:03.120
or proxy
00:13:05.339
um
00:13:06.660
I call it encapsulation light because
00:13:08.339
it's on a very micro level we can use
00:13:10.800
Lambda as a local nested functions here
00:13:13.139
we have a a method and we want to take
00:13:17.040
the two parts of the input and apply the
00:13:19.440
same behavior computation to both of
00:13:21.480
them identical computation so we create
00:13:24.660
a Lambda to do that computation and then
00:13:27.000
call it twice here
00:13:29.519
now in case you're not familiar with
00:13:32.339
multiple return values in Ruby this is
00:13:34.920
the way you do it you just create an
00:13:36.480
array and return the array and then in
00:13:38.940
Ruby you can deconstruct an array by
00:13:41.279
just giving a comma separated list of
00:13:43.079
variable names and it'll put the
00:13:44.700
appropriate array value into the
00:13:46.920
appropriate local variable name
00:13:48.720
variable
00:13:51.540
but let's say there were many lambdas
00:13:53.700
and not only one
00:13:56.459
would you notice anything interesting
00:13:58.139
about the structure of that method
00:14:00.779
you have a method with a lot of little
00:14:03.600
pieces of
00:14:04.980
isolated behaviors in them
00:14:07.380
it's kind of like a class right
00:14:10.500
so a lot of times I'm I'm writing a
00:14:13.320
method and it's getting more and more
00:14:14.940
complex and I say okay this should
00:14:16.200
really be a separate Behavior but I
00:14:17.459
won't put it into an instance method yet
00:14:18.660
I'll put it into a Lambda and I keep
00:14:21.180
going and once in a while it just gets
00:14:23.339
so complex that I realize this really
00:14:24.959
should be a class of its own or
00:14:27.600
sometimes some of them should really be
00:14:29.160
instance methods
00:14:31.200
um
00:14:33.959
so
00:14:35.880
a method with nested landas can easily
00:14:38.279
be converted into a class here with the
00:14:40.560
case we had before we just create the
00:14:42.420
compute part method
00:14:43.980
and um and we call it and this is the
00:14:47.519
way we would call it in practice I would
00:14:49.980
make these class methods so that there
00:14:52.500
would be no need to create an instance
00:14:54.060
it's kind of useless to have an instance
00:14:56.519
there so minus well even be a module
00:15:01.459
and so we have this makes these all
00:15:05.339
class methods of the module or module
00:15:07.560
methods not sure what the right name for
00:15:09.180
that is
00:15:10.160
and then they could be called in the
00:15:12.420
same way
00:15:16.440
a very common use case for lambdas and
00:15:18.540
my experience is formatters I do a lot
00:15:20.279
of command line work and so I don't use
00:15:23.519
CSS for formatting I use printf
00:15:25.860
and so that's what you'll see here
00:15:28.800
um
00:15:29.399
let's say I wanted to produce an output
00:15:31.560
like this here these last three lines if
00:15:34.139
we look at them we see that they follow
00:15:35.579
the same pattern we have a caption a
00:15:37.500
colon and a value
00:15:39.720
so
00:15:41.940
what do we do about that well let's look
00:15:44.279
at the bottom of this first the return
00:15:46.079
value is a multi-line string and because
00:15:48.540
we have the lower level Behavior
00:15:50.579
isolated into a Lambda the reader does
00:15:53.579
not have to bother filtering out that
00:15:55.740
low level implementation to understand
00:15:57.240
what's going on they say okay something
00:15:59.040
is B formatted in some way and here are
00:16:01.500
the values that are being formatted and
00:16:03.720
if they care to see the low level
00:16:05.100
implementation they can go look at it
00:16:06.959
but they probably won't and it saves
00:16:09.420
people time when they're reading
00:16:11.459
um
00:16:14.040
so there are two really good benefits of
00:16:16.740
this one of them is that the code is
00:16:18.000
more dry that is don't repeat yourself
00:16:19.800
and the other is that you're separating
00:16:22.079
high from low level code and in my
00:16:24.540
experience one of the things that makes
00:16:26.100
code the most difficult to understand is
00:16:29.040
when high and low level code are just
00:16:30.600
mixed in together
00:16:32.220
it's really important and helpful to
00:16:34.380
separate them if you can
00:16:38.399
here's another example of using lambdas
00:16:40.740
for um
00:16:42.600
uh well we're using them for formatters
00:16:45.600
but in in a list of interchangeable
00:16:47.519
formatters we have a hash here this is
00:16:50.699
from my Rex gem r-e-x-e which does some
00:16:53.699
stuff to make command line use of Ruby
00:16:55.500
simpler with inputting uh different
00:16:58.500
formats outputting different formats and
00:17:00.300
some other things and um
00:17:03.240
so you can configure this to use
00:17:05.760
different formatters and parsers and so
00:17:08.400
you would give a command line option
00:17:09.860
minus i j or something like that and it
00:17:12.600
would come in and say okay Jace that
00:17:14.280
will be converted into this symbol and
00:17:16.380
then um
00:17:17.579
uh this hash would be something that
00:17:20.160
then the configuration could just fetch
00:17:22.860
the the callable for that symbol and
00:17:26.100
plug that into a variable and then just
00:17:27.660
use that for the remainder of the
00:17:28.919
program
00:17:31.020
same thing with parsers
00:17:33.179
oh and I just wanted to mention here of
00:17:35.640
course these callables these callables
00:17:37.980
all need to have the same interface the
00:17:39.720
same take the same parameter and return
00:17:41.640
the same kind of thing in short they
00:17:44.280
need to be interchangeable
00:17:46.260
and so in in that case we were taking an
00:17:48.840
object of returning a string in the case
00:17:50.460
of parsers we're taking in a string and
00:17:51.900
returning an object
00:17:54.120
and so this is where the configuration
00:17:56.220
will put it all together it would take
00:17:58.200
those formats and then look up the
00:18:01.080
behaviors corresponding to the options
00:18:03.120
and store them in instance variables and
00:18:05.700
then use them later
00:18:09.419
lambdas are handy for Threads when you
00:18:11.640
create a thread and and launch it you
00:18:13.620
pass it a code block but using the
00:18:15.900
Ampersand you can use a Lambda instead
00:18:17.880
and so then you have all the power of
00:18:19.740
lambdas combining and that kind of thing
00:18:22.340
that can be handy at times
00:18:26.460
lambdas are closures so they carry with
00:18:28.799
them the context of the scope in which
00:18:30.780
they were defined so if there's a
00:18:33.600
local variable n which is 15 we can
00:18:36.780
output it now we could pass this to
00:18:39.179
somewhere else in the program and it
00:18:41.220
would still work
00:18:44.039
fortunately or unfortunately you could
00:18:46.140
also modify those values and that could
00:18:48.780
be a problem
00:18:50.160
but if it is a problem you can tell Ruby
00:18:53.340
oops I want this n variable to be a
00:18:56.580
local Lambda variable don't use the
00:18:58.919
enclosing scope
00:19:00.960
and and that works fine
00:19:04.440
lambdas you can call binding on a Lambda
00:19:06.600
and you'll get the binding that contains
00:19:08.100
those local variable definitions and
00:19:09.780
some other information I don't know if
00:19:11.520
that would ever be useful but it's there
00:19:13.320
if you want it
00:19:16.020
private methods are not really private
00:19:18.120
right you can call send to call them if
00:19:20.880
you want something to be really private
00:19:23.220
you could put it in a Lambda
00:19:26.880
and assign it to a local variable
00:19:29.700
and um
00:19:31.679
that would be totally invisible to the
00:19:34.500
outside
00:19:35.400
why would you want to do that I'm not
00:19:37.140
sure you know maybe if you don't want
00:19:39.140
your library users to cheat and use
00:19:41.640
things that you didn't want them to use
00:19:43.260
because you're going to change them
00:19:44.280
later Orlando would work for that
00:19:49.860
unfortunately it also means you can't
00:19:51.480
get to it with a unit test either so if
00:19:54.120
you really really need to unit test this
00:19:55.620
Behavior if it's not enough to test the
00:19:57.900
behavior of the method in which the
00:19:59.280
Lambda lives you really need to test the
00:20:01.200
behavior of the Lambda you're out of
00:20:03.179
luck you probably want to make that a
00:20:05.100
method instead of a Lambda
00:20:08.640
Lambda is a great lightweight event
00:20:10.140
handlers can be the final Lambda and
00:20:13.500
then put in a variable and then pass it
00:20:15.000
or it can just Define it in place here
00:20:17.520
without assigning it to a variable and
00:20:21.179
check out this notation and compare with
00:20:23.340
what it would look like if you were
00:20:24.419
passing a code block
00:20:25.799
it's almost the same
00:20:27.780
the only difference is the parentheses
00:20:29.400
and the arrow right so syntactically
00:20:33.419
um it's it's really no big deal to use a
00:20:36.539
Lambda instead of a block of course the
00:20:38.340
thing your calling needs to be able to
00:20:39.840
deal with it and it will be dealt with
00:20:41.280
differently on that end
00:20:46.140
for a lot of us that come from
00:20:47.340
object-oriented languages other than
00:20:48.960
Ruby we're used to using classes for
00:20:51.120
polymorphism
00:20:52.520
and so we would have classes here in
00:20:55.860
Java you'd need to create an interface
00:20:57.539
defining the even the call method
00:21:01.860
um and um it's a lot of verbosity right
00:21:05.580
compared that with this
00:21:08.580
lambdas are just so simple they're
00:21:11.100
really good in cases where you just need
00:21:12.900
something really simple
00:21:16.559
predicates are functions that return
00:21:18.360
either true or false
00:21:20.100
and we use them a lot in Ruby the select
00:21:23.400
for example
00:21:25.559
um
00:21:26.280
this is a method that
00:21:28.440
takes a filter
00:21:30.539
for messages and only adds to a list
00:21:33.780
those messages that pass that filter
00:21:35.480
this is what it might look like if we
00:21:38.039
used a Lambda as a parameter
00:21:40.320
we have a parameter call filter and we
00:21:42.960
give it a default value which is a
00:21:44.760
Lambda that returns true unconditionally
00:21:46.559
and in other words not filtered at all
00:21:49.679
where we call it we can say do this if
00:21:53.340
the filter returns true
00:21:55.679
that's pretty simple and
00:21:57.919
self-explanatory right if we contrast
00:22:00.659
this with the more conventional use of
00:22:02.280
code blocks
00:22:04.620
first of all there's no mention of the
00:22:06.539
code block and the signature now yes we
00:22:09.059
can specify the name we can specify a
00:22:12.179
name and then use that name but it's
00:22:14.400
conventionally not done usually it's not
00:22:16.080
done
00:22:17.059
and also more importantly look at how
00:22:19.799
this is being called
00:22:21.720
does that give you a clue about what's
00:22:23.940
going on in terms of the the actual
00:22:26.039
logic that it that that it's a filter
00:22:27.780
for example not really it's kind of um
00:22:31.380
obtuse in my opinion
00:22:36.659
furthermore if we need to pass multiple
00:22:38.820
behaviors we certainly can't use code
00:22:41.400
blocks because we only get one code
00:22:42.900
block per method call right so here's an
00:22:47.340
example of something that takes two
00:22:57.120
there's another
00:22:58.440
about the idea of separating high from
00:23:00.480
low-level concerns and also separating
00:23:02.700
just unrelated concerns into different
00:23:04.860
areas of the code
00:23:07.740
this is a method I was working with um
00:23:11.340
uh ingesting Network messages from
00:23:14.220
various sources and then filtering them
00:23:17.039
want to get rid of some of them I only
00:23:18.480
want some to keep and there were
00:23:21.000
different types of messages and
00:23:22.080
different types of behavior to apply to
00:23:23.580
them and the first time I approached
00:23:26.100
this I just wrote it all in one place
00:23:27.480
and I thought
00:23:28.740
there's so much going on here that's so
00:23:30.360
complex if I'm doing two things in the
00:23:33.000
same area of code then my complexity is
00:23:35.880
probably 2 squared right it's probably
00:23:37.320
four but if I can separate them out it
00:23:39.419
might be a quarter is complex and
00:23:41.340
certainly easier to read so I created
00:23:44.159
this buffered enumerable class which
00:23:46.559
just handled the process of receiving
00:23:49.320
the the
00:23:51.299
um the messages and buffering them and
00:23:53.280
then yielding them
00:23:54.620
and within that parameterized the
00:23:58.260
behavior that knew how to fetch the
00:23:59.880
messages
00:24:00.900
and the behavior that notified you in
00:24:03.960
whatever way you wanted that a chunk of
00:24:06.600
messages had been fetched maybe a log
00:24:08.760
maybe a progress indicator or something
00:24:10.740
like that
00:24:12.240
um
00:24:13.860
so lambdas are great for that kind of
00:24:16.020
thing now here's a really weird thing
00:24:18.840
that I learned and I don't know if it
00:24:20.580
really has any use in the real world at
00:24:22.320
all but you can define a class in a
00:24:25.980
Lambda using the conventional class
00:24:28.140
definition notation
00:24:30.919
you could define a class in a method by
00:24:33.360
using the fine class and Define method
00:24:35.280
that kind of thing but if you want it to
00:24:37.200
look as if it were a conventional class
00:24:39.840
definition you could do that in a Lambda
00:24:42.120
as long as that Lambda is not defined
00:24:44.940
inside a method so here we're creating a
00:24:47.700
Lambda and assigning it to a class
00:24:49.020
constant
00:24:50.880
um and if we have a method that caused
00:24:53.220
the Lambda
00:24:55.559
and then
00:24:56.820
call it
00:24:58.400
then that works
00:25:00.919
again I'm not sure if that's useful at
00:25:03.059
all but I thought it was fascinating
00:25:05.039
that you could do that
00:25:09.000
transform chains ETL light again
00:25:13.200
um
00:25:14.760
usually when we work with the numerables
00:25:16.740
we we take um
00:25:18.780
a list of values and iterate over them
00:25:21.299
with the same behavior
00:25:23.280
I'm talking about taking a list of
00:25:25.679
behaviors and iterate over them with a
00:25:28.200
single value
00:25:29.520
actually in in sequence so let's say we
00:25:33.299
have a tripler Lambda and a square or
00:25:35.520
Lambda and we put them in an array
00:25:38.279
and then we have a starting value of
00:25:39.600
four
00:25:41.059
this is called Transformers so we call
00:25:43.980
inject give it that starting value of
00:25:45.840
four
00:25:46.679
and then apply each behavior in
00:25:48.720
succession to the value accumulating a
00:25:50.760
final result
00:25:52.260
so
00:25:53.700
again I'm not so sure you know when or
00:25:55.980
how this would be useful but it's it's
00:25:57.299
really interesting that this can be done
00:25:59.100
and it might come in handy sometime
00:26:03.299
as you work with lambdas more you may
00:26:04.919
find that there's duplication that you
00:26:06.960
would want to resolve here is an example
00:26:09.480
all of these meth all of these lambdas
00:26:11.700
are multiplying n by a factor
00:26:16.919
there are two major ways to deal with
00:26:19.980
this one of them is called partial
00:26:21.299
application
00:26:22.580
which is basically creating a method or
00:26:25.140
Lambda that
00:26:26.760
pre-fills value or values in another
00:26:30.240
Lambda so here's an example we have a
00:26:33.059
Lambda which takes in a factor and it
00:26:35.640
has a Lambda here that it's returning
00:26:37.799
and it's hard coding that factor
00:26:40.200
into this Lambda and by the way this
00:26:42.900
this hard-coded factor is now immutable
00:26:45.679
and that can be handy as well
00:26:48.480
so we can call it with a 3 for example
00:26:50.820
it'll hard code that 3 here and it'll
00:26:53.940
return a Lambda that returns n times
00:26:55.980
three
00:26:57.779
the other way
00:26:59.279
oh and and that outer thing doesn't have
00:27:01.740
to be a Lambda of course it could be a
00:27:02.940
method as well because Lambda is our
00:27:05.460
first class functions um they can be
00:27:07.799
used like any variable
00:27:09.720
and so it can be returned by a method
00:27:13.980
carrying is uh oh let me check the time
00:27:16.740
two minutes
00:27:18.179
carrying is the other way to do that
00:27:21.419
um
00:27:22.620
let's say you have a Lambda that takes
00:27:25.320
two numbers
00:27:26.820
you can pre-fill a three in there by
00:27:29.880
calling dot Curry and passing three to
00:27:32.220
that and then you get that tripler
00:27:34.440
the other thing you can do is if you
00:27:36.600
want to split that out you could just
00:27:38.760
get the return value from Curry and put
00:27:41.279
it in a variable called Courier
00:27:43.380
this just might be simpler to understand
00:27:45.059
it's not something that you might want
00:27:47.220
to do I don't know
00:27:48.600
um and um then you just pass three to
00:27:51.480
that Courier and you get the tripler
00:27:55.980
and we're done thank you for listening
00:27:59.100
um
00:28:06.779
I'll leave my contact information up
00:28:08.940
there for as long as they keep that on
00:28:10.500
feel free to contact me I'd love to hear
00:28:12.779
from you thanks for listening