6

I was teaching my students how to write a function. I used a simple algorithm to determine if a char value is an actual letter (and not a digit or something else).

So I actually typed what my student said (playing dumb on purpose): "if (letter is 'A') {...}" To my surprise this didn't cause a compiler error. I added the same check for 'B' and 'C' and my program can now determine that A, B and C are indeed letters.

Why does that work? And WHAT exactly am I comparing here? I'm not actively using type comparisons, which is what the internet keeps turning up.

I did an additional experiment with other values:

 char l = 'A';
 if (l is 'A')
 {
    Console.WriteLine("l 'A'...");
 }
 if (l is "A")
 {
    // Doesn't compile.
 }

 int x = 15;
 if (x is 15)
 {
    Console.WriteLine("X is 15.");
 }
 if (x is 5.6)
 {
    // Also doesn't compile.
 }

As far as I can tell "is" functions as an extended version of the equality (==) operator that also enforces the same type. But I can't find any documentation on it.

  • 2
    See https://learn.microsoft.com/en-us/dotnet/csharp/pattern-matching – Jon Skeet Sep 16 '20 at 15:24
  • 6
    And https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/is and https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/is#constant-pattern – Jon Skeet Sep 16 '20 at 15:24
  • 2
    "But I can't find any documentation on it." Jon Skeet gave you some fish - let me give you a fishing rod: https://www.google.com/search?q=c%23+is+operator&rlz=1C1GCEA_enIL883IL883&oq=c%23+is+operator&aqs=chrome..69i57j0l5j69i58j69i60.4175j0j7&sourceid=chrome&ie=UTF-8 – Zohar Peled Sep 16 '20 at 15:27
  • I've seen `is` for pattern matching, and `is null`, but I never knew you could `is` with ints - I'm assuming that's what is valid here as a char can be converted to an int. EDIT: see the second link from Jon above, that explains it :) – DaveShaw Sep 16 '20 at 15:27
  • The language reference (as well as google) directly redirect to type comparisons. Obviously that is not what I am doing here. The reference for "if-then-else" only names the default comparators (==, >, !=, etc.) but omits "is". Also the code clearly doesn't suggest any pattern matching. As far as I can tell my code should indeed be non sense as mr. Rogier says. But still it both compiles and runs correctly. – Frederik Bonte Sep 16 '20 at 16:02
  • 3
    I don't think you looked closely enough at the links I gave. This is a *constant pattern* - see the last of the links I provided. – Jon Skeet Sep 16 '20 at 16:07
  • @Jon Skeet, thanks to the link for constant matching. Like I said, this way the "is" comparator not only returns true when the values match, but it first makes sure that the types are equivalent. – Frederik Bonte Sep 16 '20 at 16:22
  • @FrederikBonte: Well, not quite. You can match against a constant of (int) 0 with (long) 0, for example. (It will promote the int first before comparing.) And there's no concept of "equivalent" when the constant involved is `null`. But this is definitely pattern matching - and as soon as you're used to "`is` performs pattern matching" the code *does* suggest pattern matching... – Jon Skeet Sep 16 '20 at 16:28
  • @JonSkeet thanks for the explanation. I'm still trying to wrap my Java minded head around it. (To me pattern matching involves regular expressions.) However I do like the more strongly typed matching that is provided in this way. Is there any noticeable performance penalty for code like this? – Frederik Bonte Sep 16 '20 at 16:38
  • 2
    I would recommend becoming familiar with the feature and investigating further aspects for yourself, then ask a new question if necessary. Stack Overflow comment threads aren't designed to handle more questions. – Jon Skeet Sep 16 '20 at 16:42

1 Answers1

6

is might have two meanings, depending on which version of C# you have.

In older C# versions, is was short for "is assignable to" or "is assignable from", depending on how you read the code in your head. It wouldn't work for the code in your class because it expects a type on the right-hand side, but I include it here for completeness. It's also useful as an efficient and portable null check, ie variable is object is a better way to write variable != null1.

In newer C# versions, is can also be used for pattern matching. This was introduced in C# 72 and extended in C# 8, with more coming in 9. Specifically, the code in the question creates a Constant Pattern expression.

Here's another fun way to see this work. Coming in C# 9, instead of writing a check like this:

if (!string.IsNullOrEmpty(mystring))

You could instead write3

if (mystring is {Length:>0})

Which is nice because it's shorter and you could make an argument removing the negation makes it easier to understand.4


  1. At least, according to one of the developers on the C# team at Microsoft. But what would he know? He only built the thing.
  2. Really, C# 6 if you count exception filters.
  3. Jared Parsons again.
  4. I'd reject that argument on the grounds any gains in removing the negation are less than the subtlety introduced in how we validate for null. But you could try the argument ;) And before anyone asks, I have no idea at this time how the two options perform.
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794