Need help understanding lambda statements and delegates
I'm extremely confused about the syntax and it's hemorraging my ability to work on other stuff (LINQ, middleware)
How do I even begin comprehending the syntax? I keep rereading the MSDN documentation and watching youtube videos and nothing makes sense
108 Replies
What exactly is confusing you? You can write any lambda as a full method, if that helps?
More details please. What exactly is confusing you?
Yea so why does this look utterly different from the middleware lambda?
I know a lambda basically lacks a method name
It's just parameters => dosomething
But why is the syntax so drastically different between lambdas used in middleware, delegate, and other functions?
different in what way?
The parameters aren't even lined up the same way
I don't get it
In the first one the return type is int and input is string
But they are both inside of func <>
And then in the second, both context and next are input parameters and there is no return type specified in the lambda
Why is there no consistency between the syntaxes?
There are no patterns
Or at least my stupid brain can't see the patterns
I can only recognize that => indicates to dosomething
But i keep getting tripped up by the lambda signature
It seems that the signature changes every time it's used and it drives me crazy because I can't figure out why
Ok for example what does that even mean?
parse
is the lambda's name
just like any other variable
int myInt = 0;
string myString = "";
i could have named it myLambda
if you prefer that
input
is the string
parameter's name
just like in the full method body below
string input
i could have wrapped input
in parens if you prefer that
Func<string, int> myLambda = (input) => int.Parse(input);
what you're using in app.Use()
is an anonymous function, one which doesn't have a nameBut why is input even there, and missing a type declaration?
so all that remains is
(input) => int.Parse(input);
the type declaration is in the Func
type
Func<string, int>
takes in one string parameter, and returns one integerSo the return type of a lambda is always the last value of the declaration?
indeed
Return would be bool
Return would be List<int>?
mhm
So then the variable names (x, y) correspond in order with the int,int declarations in Func (for the first lambda)?
yup
If it was Func<int,string,int> trial = (a,b)=>
It would be int a, string b
yup
I still dont get this
you can actually declare them explicitly
Ah
But it needs to match the Func<> declaration?
yeah
Im still having trouble mapping the app.use one in my head
well, just like you don't need to do
but instead can just skip the variable declaration;
the same goes for lambdas
Ohhh so you excluded the because inserting the lambda directly into the function doesn't require you to give the lambda a variable name
But async keyword remains?
the
async
is there because the return type of your lambda is a Task
or a Task<T>
(depending on if it returns anything)
and Task
s can be awaitedI have no idea what a Task<T> is
you're gonna have to learn that if you're gonna wanna do web dev
Oh msdn documentation shows you can do Task<int>
T
would be int
in that case, yesI feel like I need a whole different thread for clearing up understanding on Tasks
Ik Task is a return type in itself
But thats sort of digressimg
Ok back to lambdas
In this case the entire {} chunk is the dosomething part right
yeah
And the entire lambda is just thrown into app.use
Hmm
Lemme grab the delegates code i was confused about for 2 months
Gimme a bit
ok
//defining a new datatype called IntOps that represent method that accept int and return an int
//Once we declare this, we can create a method that uses this delegate type
//we can use the parameter just like a normal method in our method
//method Add10 match the signature of the IntOps delegate
//I don't understand what this means, or why
//Calling the method that accepts a delegate (using anonymous method)
//Calling the method that accepts a delegate (using delegate)
Ig here my issue is, what is an anonymous function and what does it have to do with lambdas?
Ok so if we compare the one I just posted to yours (with explicit declaration)
Oh so it's replacing the Func<> declaration with IntOps myOp
But why?
What even is IntOps myOp and why does it apply a lambda
Ok, so
Is declaring a delegate that returns int, of name IntOps, that accepts parameter int n
https://www.tutorialsteacher.com/csharp/csharp-delegates
Based on the graphic in this thread
---
Oh so it's just showing 3 different ways of assigning a method to
First way is by assigning the method name directly (Add10)
Second way is by assigning an anonymous method (I don't really get this)
Third way is assigning using a lambda
===
Ok so in some videos they refer to lambda functions as anonymous functions. But it seems that in this code example they are not the same?
Anonymous function example
Lambda expression example
@Ero are anonymous functions the same thing as lambdas? If they are, why does the syntax differ?
There is old and new syntax: old:
delegate (int x) { return ...;}
, new: x => ...
The =>
syntax is called lambda syntaxSo what is the delegate(int x) syntax called
Have you played with sharplab?
Nope
It's probably worth playing with. https://sharplab.io
SharpLab
C#/VB/F# compiler playground.
See what the different syntaxes generate
They all end up generating a normal C# method under the hood
That would be great for actually learning yeah but I'm trying to understand what the delegate(int x) syntax is called
Does it have a name?
I don't know if it had a specific name. You used the syntax to declare what was called an anonymous function mainly, iirc. There are lots of names for the same things
in my notes it's labelled an anonymous function
in the videos i've seen they refer to lambdas as anonymous functions.
Are anonymous functions == lambdas or are anonymous functions an umbrella term that includes lambdas?
Iambdas, anonymous methods, closures, all effectively the same thing
If they are the same thing then why does the syntax not have =>
Why does it have delegate() instead
Does this mean delegate() is a method used to designate a lambda/anon method/closure?
strictly speaking in C#, the
=>
syntax is a lambda. You can use that to declare an anonymous function/closure, but you can also use => to declare a linq expression (though that's an added complication you can probably ignore for now)
The old and new syntaxes do the same thingOh yeah I did see linQ expressions with ()=>
I wanted to ask about those too
I was really confused when I first saw them
The complication there linq is in two parts: you can use the same
=>
syntax to declare both an inline method, and something which an be translated to SQL. But let's ignore that for nowHow do I differentiate between the two?
All these do the same thing:
In the first two, we're writing a method ourselves and creating the delegate instance
doubler
from that method. In the latter two, we're using different syntax to write the method inline, and the compiler is creating the method for us under the hood, and then creating the delegate instance from that method
You don't see the 3rd syntax any more -- the 4th one is a replacement which is betterWhats the purpose of doing
= new Func<int,int>(Method) if = Method achieves the same thing?
The way of writing the method inline is variously called a closure, lambda, inline method, anonymous delegate... All basically the same thing, coming from different languages and paradigmes
= new DelegateType(Method)
came first, then = Method
was added later as a shorthand to reduce the boilerplate. It's still very occasionally useful
= Method
still generates new DelegateType(Method)
under the hoodFunc<> is new DelegateType?
Why does c# name the methods relating to lambdas things that begin with 'delegate..'?
I thought delegates and lambdas were separate concepts
Yes. The framework declares it as
public delegate TResult Func<in T, out TResult>(T arg);
: https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Function.cs,7
A delegate is its own thing, similar to but separate from a class and struct. A delegate is a thing which points to a method, and can be used to invoke the method. You declare the delegate type with delegate returntype DelegateType(param1, param2, ...)
(and the type describes the delegate's parameters and return type), and instantiate it with new DelegateType(method)
(although as we've seen, the compiler will add the instantiation for you to reduce boilerplate most of the time)Oh so lambdas are just one way of assigning a method to a delegate/method pointer?
They're a way of declaring a method inline, and creating a new delegate instance which points to that method, yes
Are delegates ref type or value type?
Pointer seems to indicate ref type
They're immutable reference types
Confusingly, they can be combined:
SomeDelegate result = delegate1 + delegate2
. Invoking result
will invoke both delegate1
and delegate2
. Events are built around that bit of functionality, although you don't see it used outside of eventsI haven't covered events yet, probably need to cover linQ when I wake up in the morning
Will be back with more questions about lambda syntaxes but in linq
https://sharplab.io/#v2:EYLgHgbALANAJiA1AHwAICYCMBYAUKgZgAIMiBhIgbzyNpONSiIFkAKASiprp9QFYAPAEsAdgBcYRUWIB8ROAHsArsAA2AUwBORALxEwuuQYBURdAG5utAL55rQA. See there. There's some extra stuff around caching the delegate instance, but you should be able to see what's goind on
SharpLab
C#/VB/F# compiler playground.
Wdym by caching š³
It put the method
x * 2
(which it called <M>b__0_0
) on a new generated inner class called <>c
, and then did new Func<int, int>(<>c.<>9.<M>b__0_0)
So if the code Func<int, int> doubler = x => x * 2;
is run lots of times, it only needs to create one delegate instance, which makes it cheaper
https://en.wikipedia.org/wiki/Cache_(computing)Oh you mean the compiler adding the delegate instantiation boilerplate and then caching the resulting delegate
Bruh
yep
Guh I wish I could add you so it would be easier to reach than pinging you in this thread š„²
Ah, so this
requires IntOps to define the return and input param type in because there's no Func<int,int> definition
And then this code just accepts the lambda assigned to IntOps as an input parameter, which it then manipulates int[] arr with
===
Then I have a question, what is the difference between these two?
and
you can assign a corresponding lambda statement to both of these. What purpose does each serve?
There is no real difference
These are is the definitions of
Func
from the official repo
https://github.com/dotnet/runtime/blob/57bfe474518ab5b7cfe6bf7424a79ce3af9d6657/src/libraries/System.Private.CoreLib/src/System/Function.csGitHub
runtime/Function.cs at 57bfe474518ab5b7cfe6bf7424a79ce3af9d6657 Ā· d...
.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps. - runtime/Function.cs at 57bfe474518ab5b7cfe6bf7424a79ce3af9d6657 Ā· dotnet/runtime
Both work when inserted into
Just that to use a delegate function, you need another line
lol it supports up to a max of 16 input params
Yeah š
well the Func<> syntax certainly seems more convenient considering that you don't need to declare a
but is there any advantage to using the delegate int IntOps(int n) method at all?
I don't know about others, but I personally use
Func<>
or Action<>
most of the times unless I want to have a type name.wdym by type name
Very rarely you might use it for
ref, out
because Func
and Action
don't allow thatyou mean like ?
Basically instead of
public void Test(Func<int, int, int, string> callback)
public delegate string CallbackDelegate(int param0, int param1, int param2)
and
public void Test(CallbackDelegate callback)
Yeah, with Func
and Action
you can't ref
and out
oh
gdi
are you talking about delegate name?
I still don't quite understand
Oh sorry, I didn't clarify, yes I was taking about the the delegate name
It might be easier for the caller to understand the purpose of it.
Or it might save you typing extra characters if you use that delegate a lot in your code
I also have a question- when using top level statements (TLS), it seems that the delegate variable holding the relevant lambda can be declared at any point in the code (before or after the method calling it)
Why is this possible?
Whereas other variable declarations must occur in the proper scope ahead of the TLS call
Wdym, I don't think you can call it before the variable is declared
š¤
I'll screengrab when I get back to the computer
How would I go about looking for the definitions of app.Use from the original asp repo?
app?
Middlewares
Oh
Here's the default implementation for
IApplicationBuilder
GitHub
aspnetcore/ApplicationBuilder.cs at 51fc6824e30016404964fc96a4a098a...
ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux. - aspnetcore/ApplicationBuilder.cs at 51fc6824e30016404964fc96a4a098a764b...
it's callable
It's declared before getting called, no?
wait if that's the declaration then what does this do
Oh, that's the
type
declaration, this is similar to
class MyClass {}
ohhh
is it correct to call it the class declaration?
the syntax is green indicating that Testing it's a class/object
well, it's a delegate declaration not a class
what does green coloration in the IDE indicate
object?
I think with the default visual studio config it indicates a
Type
so in other word, classes and delegates are types?
A class is a type, let's think of it that way when you do
class MyClass {}
And instantiate it like this
var myClassInstance = new MyClass()
what's the type of myClassInstance?but if you assign a variable to a type, it's not green
Try
Int32 iUse = 10
What is it's color?Green, but it's a different shade from the object/delegate green
Int32 is a struct
Yup, it's a struct, and the reason it has a darker shade is visual studio is suggesting to substitute it with int
int
is a keyword in c#, that keyword map directly to the Type Int32
oh so blue indicates keywords
That's right š
that's so fascinating wtf
why are read only types like int considered keywords?
because they are defined as keywords in ECMA-334 (the standard specs for C#)
And it's more intuitive to just do
int
short
instead of Int32
Int16