tags:

views:

156

answers:

5

1) According to my book, is operator can check whether expression E (E is type) can be converted to the target type only if E is either a reference conversion, boxing or unboxing. Since in the following example is doesn’t check for either of the three types of conversion, the code shouldn’t work, but it does:

  long l;     // EDIT - I forgot to add this line of code in my initial post
  int i=100;
  if (i is long) //EDIT - in my initial post I've claimed condition returns true, but it really returns false
           l = i;

2)

a)

    B b;
    A a = new A();
    if (a is B)
        b = (B)a;
    int i = b.l;


    class A { public int l = 100; }
    class B:A { }

The above code always causes compile time error “Use of unassigned variable”. If condition a is B evaluates to false, then b won’t be assigned a value, but if condition is true, then it will. And thus by allowing such a code compiler would have no way of knowing whether the usage of b in code following the if statement is valid or not ( due to not knowing whether a is b evaluates to true or false) , but why should it know that? Intsead why couldn’t runtime handle this?

b) But if instead we’re dealing with non reference types, then compiler doesn’t complain, even though the code is identical.Why?

        int i = 100;
        long l;
        if (i is long)
            l = i;

thank you

+3  A: 

The real difference is that in the int case, you are talking about the definite assignment of a field (l). Fields are always definitely assigned (even without the =100). In the B case, you are talking about the definite assignment of the local variable (b); local variables do not start as definitely assigned.

That's all it is.


int i=100; if (i is long) //returns true, indicating that conversion is possible

1: I don't think this returns true at all; for me it shows an IDE warning about never being true. Looking in reflector, the compiler completely removes this branch. I guess the compiler is obliged to at least compile on the grounds that it could (in theory) box and test. But it already knows the answer, so it snips it.

2: I still get the "unassigned variable" compiler error; due to "definite assignment"

Marc Gravell
1) “The real difference is that in the int case, you are talking about the definite assignment of a field (l). Fields are always definitely assigned (even without the =100). In the B case, you are talking about the definite assignment of the local variable (b); local variables do not start as definitely assigned.”I made an error in my original post since I didn't include code that clearly shows that variable l( as used in my first question) is local variable ( will edit my post ). Thus, knowing that l ( in the int case ) is local variable, l doesn't get initialized to value 0
flockofcode
2) “I don't think this returns true at all;” My mistake, I forgot to add {} and instead of having if (i is long) { l = i; Console.WriteLine(“something”);} I had …3) “I still get the "unassigned variable" compiler error; due to "definite assignment"” To what question are you referring to?
flockofcode
@flockofcode - well, I implicitly assumed you'd also have some code that attempts to *use* `l`...
Marc Gravell
Assuming that variable l ( Q2b ) is local variable, then shouldn't compiler report an error even if no code ( following the if statement ) attempts to use l?
flockofcode
@flockofcode - not if you don't attempt to read it, no.
Marc Gravell
Due to my sloppiness I thought that compiler complains when encountering the following code --> B b; A a = new A();if (a is B) b = (B)a; <-- but it doesn't ( unless we attempt to read b ), and thus behavior of compiler is consistent with behavior when it encounters the following code --> int i = 100;long l; if (i is long) l = i; <-- All good then ;) . Thank you all for your help
flockofcode
+6  A: 

This has nothing to do with the is operator. The compiler sees that there are two possible paths, only one of which will assign a value to b.

When dealing with value types, the compiler knows that l gets implicitly initialized to the value 0.

Stephen Cleary
"When dealing with value types, the compiler knows that l gets implicitly initialized to the value 0." Uh, I made an error in my original post since I didn't include code that clearly shows that variable l( as used in my first question) is local variable ( will edit my post ). Thus, knowing that, l doesn't get initialized to value 0
flockofcode
@flockofcode, value types are inherently initialized and declaration time, even if they're local variables. Reference types are not.
Kennet Belenky
I'm probably missing the point you're trying to convey, but anyways ... if what you're saying is correct, then why does the following code result in "use of unassigned local variable a1" --> int a1;int a2 = a1; If a1 was really initialized at declaration time, then why did compiler report an error when we tried to assign a value of a1 to variable a2?!
flockofcode
+2  A: 

The compiler behaves correctly - why should it compile without errors if there is a use of an unassigned variable? You cannot work with b.l if b is unassigned as the compiler checks that there is a code path that does not instantiate b which is why it throws an error ...

Marius Schulz
+2  A: 

In your code, class B derives from A. This means:

a is B // evaluates to false
b is A // evaluates to true

This means that the body of the if block won't be entered, and b will not be assigned.

Stephen Cleary also has a point. I don't know how sophisticated the compiler is when evaluating if values are assigned.

Kennet Belenky
+2  A: 

Okay, the MSDN says on is:

The is operator is used to check whether the run-time type of an object is compatible with a given type.

An is expression evaluates to true if both of the following conditions are met:

  • expression is not null.
  • expression can be cast to type. That is, a cast expression of the form (type)(expression) will complete without throwing an exception.

That would fit pretty well with 1, but 2 is another topic and correct (think about it).

However, the following code writes 0 to the output:

    int i = 1;
    long l = 0;
    if (i is long)  {
        l = i;
    }
    Console.WriteLine(l);

Therefore it seems that the note in the is MSDN documentation is correct as well:

Note that the is operator only considers reference conversions, boxing conversions, and unboxing conversions. Other conversions, such as user-defined conversions, are not considered by the is operator.

Lucero
I think the word "run-time" is the important distinction here. The compiler is not working at run-time and it won't infer that a is a B. With the primitives, they are always initialized.
Dave White
Yes, what I meant is that the *behavior* of the compiler is correct. Sorry if that was unclear.
Lucero