✅ Anonymous and lambda function in C#
Hello guys, I was just reading a bit about lambda functions. From what I've understood, it's an inline style of declaring a function definition. We use it if for example we want to only execute a function once. They are used together with delegates, to store the function reference and just invoke the function as needed.
Lambda function relies on delegates to work?
E.g of lambda functions:
20 Replies
Lambdas and delegates are related but distinct.
A delegate is a essentially the "type" of a method. It says "if you give me these arguments then I'll give you back a value", so it's a value you can pass around and potentially call with some arguments.
A lambda isn't necessarily reliant on the existence of a delegate, but in practice you have to use a delegate to be able to use a lambda. A lambda is just a normal method, except it doesn't have a name, you just declare it in-place. Since it doesn't have a name, the only way you can actually invoke it is by assigning it to a delegate and then invoking that.
yepp I see, thanks !
Also, you can actually assign a lambda to
var
and the compiler will figure out what delegate type it should be for you Lambdas are super useful for letting the caller of a method "tweak" how it works. A classic example is the
.Where
method from LINQ
.Where
takes a predicate, a function that takes in a T
and returns a bool. In this case, T
is int
.
it then calls the predicate function once for each value in the sequence. If the bool is false, it does nothing. if the bool is true, the value is returned as part of the resulting sequence from .Whereoh yeah, thanks !
ah I understood the syntax used in Select/Where method now, thanks !
by the way, why is it important to put the .ToArray() method ? why can't we omit it or if we omit it, what happen ?
what happens behind the scenes? like even should be an array of even numbers
but we didn't give it a size at first
This is required because LINQ methods, such as
Where
, work as an IEnumerable. These are special types which do not actually represent a collection, but rather a "blueprint" which then gets invoked by calling ToArray()
or another method that generates a collection. The convenient thing is that you can chain LINQ methods and only when ToArray
or something else is called, it iterates and allocates a collection. This is different compared to Javascript which has similar syntax, but each call makes a new collection. This is quite wasteful.
You can make your own metod that returns IEnumerable. You'll see you have a new keyword yield
that indicates a line that returns a collection entry, essentially. When you call the method, it invokes until a yield keyword. The returning IEnumerable can then be stepped through with special methods on the interface, such as moving to the next yield statement, until the code finishes and returns no more yield keywords. Alternatively you can also just call ToArray
again.
Note that methods such as ToArray
does this exact system of stepping through an IEnumerable until no more entries are found. It's just a convenient method for it.
Note the IEnumerable by itself doesn't necessarily define all this logic. It only defines the "enumerator" which is the thing you end up iterating (for example, this could be iterating your method).
It's kind of a complex topic. You might want to give this a shot yourself
https://learn.microsoft.com/en-us/dotnet/api/system.collections.ienumerable?view=net-9.0yeah, in fact, while seeing this syntax, I compare it to javascript in my head, I thought they were doing the same thing, but this isn't the case?
The List is an example of a type implementing IEnumerable (it implements IList, which implements ICollection, which finally implements IEnumerable).
It provides this enumerator: https://github.com/microsoft/referencesource/blob/master/mscorlib/system/collections/generic/list.cs#L1140
The syntax is weird, but note the method
MoveNext
and property Current
. MoveNext
moves the enumerator to the next "yield" which in this case is just the next index in the list since it's already a well-formed collection, and Current
returns the current item pointed from the collection.GitHub
referencesource/mscorlib/system/collections/generic/list.cs at mast...
Source from the Microsoft .NET Reference Source that represent a subset of the .NET Framework - microsoft/referencesource
LINQ's
Select
is Javascript's Map
and LINQ's Where
is Javascript's Filter
It's just that all of Javascript's functions make a new array which is wasteful. They have something called iterators themselves which work the same as IEnumerables, though that's not used hereyeah, iterators are not the same thing as enumerators, I guess ?
Fun fact, they are actually considering the "pipeline" syntax which seeks to fix this exact issue: https://www.youtube.com/watch?v=k4xuEl6TmT4
Jack Herrington
YouTube
Javascript's New Pipeline Operator Is Awesome!
If you like .map, .filter, .reduce, etc. you'll love the proposed new pipeline operator.
Proposal: https://github.com/tc39/proposal-pipeline-operator
👉 ProNextJS Course: https://pronextjs.dev
👉 Don't forget to subscribe to this channel for more updates: https://bit.ly/2E7drfJ
👉 Discord server signup: https://discord.gg/ddMZFtTDa5
👉 VS Code the...
They're actually very similar
The issue is they exist on method level, and it's not something that can be extended to things like
map
and pipedYep, will just read a bit about the IEnumerable and came back
yep I see, will just do further readings and came back
Alrighty
JS becoming F#
Ok so I've read a bit. From what I've understood, something that implements the IEnumerable means that a sequence can be iterated over. It contains a single method GetEnumerator(). This returns an enumerator object that will allow us to enumerate through the sequence one at a time.
The Enumerable sequence executes using "lazy execution" meaning each item in the collection is iterate one at a time (only when needed), we can pause/stop it whenever we want. (hmm I don't know if we can really pause it here, what I read is that an iterator remembers state (using yield return keyword internally I thing), but does this applies here?)
Now concerning why we must use the ToArray(), it's because the Select/Where clause return an Enumerable; in order to have the result, we must explicitly convert them into a collection like the ToArray() method (in Javascript, this is done implicitly I guess like you said, so every time a new array is created and it's wasteful, like you said earlier.)
here, the logic might be defined by another interfaces for example ? like when yield should stop something like that?
En enumerator just defines how you go through the source object and how it fetches the items it intends to return. You can "pause", but the whole system uses the two aforementioned methods (and
Reset
to reset iteration) so it's not like there's a start/end method. It's up to you
You can't pause ToArray
because it intends to efficiently create an array. Pausing would be silly. Otherwise you'd have to make your own enumerator if you want this.yep I see
The interface does not define anything. It's kind of code magic in the background. Classes will implement the method, or you can return the interface in which case C# kind of does it for you in the background.
make sense now, I understood how all this work behind the scenes (just an overview but I understand now) with enumerator, iterators and collections that implement the enumerable interfaces, etc..., thanks !!