3

I just saw the following answer: Is there a better way to create acronym from upper letters in C#? and it has the following code:

string.Join("", s.Where(char.IsUpper));

How does the char.IsUpper work here? (Instead of x => char.IsUpper(x))

Community
  • 1
  • 1
ispiro
  • 26,556
  • 38
  • 136
  • 291

4 Answers4

10

char.IsUpper is a method group, which itself takes a char and returns a bool, so it's a valid predicate for use with Where().

The code is referencing the method by name in much the same way as you would with any other method when specifying a delegate, instead of directly invoking it, so the parentheses aren't necessary.

The parentheses are necessary if you're wrapping it in a lambda expression x => char.IsUpper(x), because you're calling the method and returning the result, within the expression.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • @ispiro Rephrasing (this is not exactly correct, but hopefully helps clarify nonetheless): the parameter for `Enumerable.Where` has to be a function. It can be a function defined inline (`x => char.IsUpper(x)`), or it can be a preexisting function. `char.IsUpper` is a preexisting function, of the right type, so is a valid argument. –  Aug 08 '13 at 16:42
  • Is is some kind of polymorphism? – Armen Aug 08 '13 at 16:46
  • @Armen: No, it is not. – jason Aug 08 '13 at 16:50
  • @hvd: No. `char.IsUpper` when used as is done here is *not* a function. It is a method group and a method group to delegate conversion is performed for the invocation to be legal. – jason Aug 08 '13 at 16:50
  • @Jason It is not a function *call*. It *is* a function. You're right about the conversion to a delegate type, I intentionally omitted that from my comment to make it easier to understand and that is what I meant by "this is not exactly correct". –  Aug 08 '13 at 16:54
  • @hvd: No. When you write the syntax `s.Where(char.IsUpper)` the `char.IsUpper` that appears there is *not* a function. It is a method group: these are not the same thing. – jason Aug 08 '13 at 16:55
  • @hvd: In this particular case where there is exactly one overload of `char.IsUpper` it's easy to get confused and think they are the same thing. But in a case like `Console.WriteLine` which has billions and billions of overloads, suddenly the difference becomes very obvious. When you have `void M(Action action)` and you say `M(Console.WriteLine)` the `Console.WriteLine` there is a method group. The compiler performs a method group to delegate conversion using the overload `Console.WriteLine(int)` to do the conversion. – jason Aug 08 '13 at 16:58
  • @Jason Actualy `Console.WriteLine` has 19 overloads – Tyler Aug 08 '13 at 17:00
  • @Jason Given three functions, `bool f(int)`, `bool f(char)`, and `bool g(Predicate)`, I would still say that the `f` in `g(f)` is a function. It is the first of these three. That same letter `f` could also refer to the second function in other contexts. Technically, you're completely correct, but you're being technically completely correct in a way that won't help people understand. You're treating the method group to delegate conversion as a single operation. I'm not saying that's incorrect, I am saying that isn't helpful. –  Aug 08 '13 at 17:08
  • @hvd: [Technically correct---the best kind of correct](http://www.youtube.com/watch?v=hou0lU8WMgo). :-) – jason Aug 08 '13 at 17:37
3

char.IsUpper refers to a method group which is passed to the Where function as a typed delegate via an implicit conversion which you can read in the Covariance and Contravariance in C#, Part Three: Method Group Conversion Variance article by Eric Lippert.

Community
  • 1
  • 1
Michael Goldshteyn
  • 71,784
  • 24
  • 131
  • 181
1

I believe char.IsUpper (without parentheses) evaluates to a reference to the method, that can be passed as a predicate. If you added parentheses, that would just immediately invoke the method and attempt to pass the result instead of passing the method itself.

Esailija
  • 138,174
  • 23
  • 272
  • 326
0

Where<char> takes a Func<char, bool> as a parameter. By using x => char.isUpper(x), you are creating a new Func to be used by Where. However, the toUpper method, takes a char, and returns a bool. Therefore, it can be used directly as the parameter for Where.

cadrell0
  • 17,109
  • 5
  • 51
  • 69