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
  • 25,277
  • 32
  • 126
  • 258

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
  • 665,005
  • 155
  • 1,345
  • 1,328
  • I don't understand your answer. You're telling me `char.IsUpper()` works. That's the part I _do_ understand. What I don't understand is `char.IsUpper`. – ispiro Aug 08 '13 at 16:39
  • @ispiro: I updated my answer. – BoltClock Aug 08 '13 at 16:40
  • Thanks.​​​​​​​​​​​​​​​​​​​​​​​​​ – ispiro Aug 08 '13 at 16:42
  • @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
  • @hvd Thanks.​​​​​​​​​​​​​​​​​​​​​​​​​ – ispiro Aug 08 '13 at 16:43
  • 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
  • @BoltClock: Thank you for updating your answer. You were about to get the "this answer is incorrect" comment. :-) – jason Aug 08 '13 at 17:00
  • @Jason Actualy `Console.WriteLine` has 19 overloads – Tyler Aug 08 '13 at 17:00
  • @Jason: Haha - I *am* reading these comments as they happen. And believe it or not, I'm not nearly as familiar with C# as a lot of other people despite my gold badge :) – BoltClock Aug 08 '13 at 17:08
  • @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
  • 68,941
  • 23
  • 129
  • 179
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
  • 134,577
  • 23
  • 263
  • 318
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
  • 16,721
  • 4
  • 50
  • 68