Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# lambda expressions without variable / parameter declaration?

Tags:

c#

.net

lambda

linq

What's it called when a method that takes a lambda expression as the parameter, such as Enumerable.Where, is invoked without actually declaring a variable or method parameter in the expression?

For example, I'm familiar with this lambda expression syntax:

public string GetDigits(string input)
{
    return new String(input.Where(i => Char.IsDigit(i)).ToArray());
}

However, I was surprised to find out that this can also be written as:

public string GetDigits(string input)
{
    return new String(input.Where(Char.IsDigit).ToArray());
}

What's going on in that second snippet, where the Char.IsDigit() method is (apparently) being called with an implicit parameter? What is this syntax called?

like image 399
Jon Schneider Avatar asked Jun 17 '15 14:06

Jon Schneider


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr. Stroustroupe.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


2 Answers

Methods don't accept lambdas as parameters. They accept delegates as parameters. A lambda is just one way of creating a delegate.

Another way is supplying a method group, as is done in your second example, which can be converted to a delegate.

A similar way is to use the anonymous method feature. This was more or less replaced with lambdas when they were added though, so you don't see it much. Your example using that syntax would be:

Func<char, bool> predicate = delegate(char c) { return Char.IsDigit(c); };

Yet another way would be to create a delegate using Delegate.CreateDelegate. (This isn't something you see all that often though.)

A final way is to have a delegate variable that you got from somewhere else. (That somewhere else would have created the delegate using one of these other options.)

What's going on in that second snippet, where the Char.IsDigit() method is (apparently) being called with an implicit parameter? What is this syntax called?

It's not being called. That's the whole point. We're trying to create a delegate. A delegate is an object that keeps track of a method to be invoked, and an object that it should be invoked on. You can then invoke the delegate and it will call the method that was used to create it. So here you're not calling IsDigit, you're creating a delegate that is pointing to the IsDigit method, and that will call it whenever that delegate is invoked.

When you use a lambda you're creating a new method, possibly in a new class, (neither of which have a name you can refer to, but they'll have one at runtime) and the body of that anonymous method will call IsDigit. The lambda then resolves to a delegate pointing to that anonymous method, which maintains the semantics of the other example of having a method that when called, calls an anonymous method which, in its implementation, calls IsDigit. It's adding an extra layer of indirection (that may or may not just get optimized out at runtime) to accomplish the same thing.

like image 142
Servy Avatar answered Oct 15 '22 20:10

Servy


The signature of Enumerable.Where is:

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate
)

This:

input.Where(i => Char.IsDigit(i))

is equivalent to writing:

Func<char, bool> temp = i => Char.IsDigit(i);
input.Where(temp);

so it creates an anonymous function with a parameter i that calls Char.IsDigit.

This:

input.Where(Char.IsDigit)

is equivalent to

Func<char, bool> temp = Char.IsDigit;
input.Where(temp);

that is equivalent to:

Func<char, bool> temp = new Func<char, bool>(Char.IsDigit);
input.Where(temp);

so it creates a delegate to Char.IsDigit and then passes it to input.Where.

So the second one removes the "man-in-the-middle" (the anonymous function). In this particular case it is "legal" because the i parameter of the anonymous function is passed "as is" to Char.IsDigit. It would have been different if it was:

input.Where(i => !Char.IsDigit(i))

in this case, you can't remove the man-in-the-middle (the anonymous function).

There is no name for all of this (or you could call the first "creating and passing a delegate to an anonymous function" and the second "creating and passing a delegate created from a method group"... but they aren't beautiful catchphrases, they are more a description of what you are doing)

like image 27
xanatos Avatar answered Oct 15 '22 20:10

xanatos