An "is" operator puzzle, part one

An "is" operator puzzle, part one

Rate This
  • Comments 21

It is possible for a program with some local variable x:

bool b = x is FooBar;

to assign true to b at runtime, even though there is no conversion, implicit or explicit, from x to FooBar allowed by the compiler! That is,

FooBar foobar = (FooBar)x;

would not be allowed by the compiler in that same program.

Can you create a program to demonstrate this fact? This is not a particularly hard puzzle but it does illustrate some of the subtleties of the "is" operator that we'll discuss in the next episode.

  • This can happen if FooBar is a type parameter to the method containing the code and x is a variable of a known type that isn't known to be convertible to FooBar, right?

    something like:

    void Frob<FooBar>() {

     int x = 1;

     bool b = x is FooBar;

    }

    Frob<int>();

  • We're having a fun time trying to solve this in the C# StackOverflow chat room.  Thanks for the puzzle Eric!

  • bool b = (object)x is (object)FooBar?

  • Gah, Ignore that, I misread the problem.

  • static void M<T>(T x)

           {

               bool b = x is FooBar;

               FooBar foobar = (FooBar)x;

           }

  • Michael beat me too it, but here is a example you can just dump into LINQ Pad if you want to play:

    void Main()

    {

    var x = new FooBar();

    CheckForFoobar<FooBar>(x);

    }

    public class FooBar

    {

    public int test;

    }

    public static bool CheckForFoobar<T>(T x)

    {

    bool b = x is FooBar;

    //Will not compile

    //FooBar foobar = (FooBar)x;

    b.Dump("b");

    return b;

    }

  • void Main()

    {

    dynamic x = new FooBar();

    bool b = x is FooBar;

    Console.WriteLine(b);

    x = null;

    /* Uncomment this line to create compiler error: Cannot convert null to 'FooBar' because it is a non-nullable value type. */

    //FooBar foobar = (FooBar)x;

    }

    public struct FooBar

    {

    }

  • I, too, tested my code in LINQPad. Just realized that it does not produce a compiler error, but a RuntimeBinderException exception at runtime.

  • What if FooBar is abstract? Then "is" can succeed, while instance creation can't.

  • This seems more like a subtlety of explicit conversions than a subtlety of the 'is' operator, since the 'is' operator is translated to an IL 'isinst' instruction under the hood.  So I took a minute to look it up in the spec, and the spec even admits to it being a subtlety:

    "The above rules do not permit a direct explicit conversion from an unconstrained type parameter to a non-interface type, which might be surprising. The reason for this rule is to prevent confusion and make the semantics of such conversions clear."

    This is because type arguments can't be substituted at compile-time, to know what explicit conversions exist.  The allowable conversions for the 'is' operator, however, are all evaluated after type arguments have been substituted.  

  • I think any developer who's attempted generic math has run into this:

    public void DoMath<T>(T value)

    {

       if (value is int)

       {

           DoIntMath((int)value);

       }

    }

  • Hello Eric.

    My guess is the below one, although I think you meant something smarter.

    namespace NS

    {

     using Bad = FooBar;

     class FooBar

     {

       static void Main()

       {

         Bad x = new Bad();

         bool b = x is FooBar;

         Console.WriteLine(b);  //returns true

       }

     }

    }

    Cheers

  • Nope, forget it...it's an alias, thus the type is the same, and any cast/conversion would be allowed.

  • var x = new TypedReference();

    bool b = x is object;

    Console.WriteLine(b);

    object o = (object)x;

  • Maybe this?

       class Program

       {

           static void Main(string[] args)

           {

               dynamic x = new FooBar();

               bool b = x is FooBar;

               Console.WriteLine(b);

               Console.ReadLine();

           }

           class FooBar

           {

           }

       }

Page 1 of 2 (21 items) 12