Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is 'is' implemented as 'as'?

Given that this is a very natural use case (if you don't know what as actually does),

if (x is Bar) {    Bar y = x as Bar;    something(); } 

is effectively equivalent (that is, the compiler-generated CIL from the above code will be equivalent) to:

Bar y = x as Bar; if (y != null) {     y = x as Bar; //The conversion is done twice!     something(); } 

EDIT:

I guess I hadn't made my question clear. I wouldn't ever write the second snippet as it's of course redundant. I'm claiming that the CIL generated by the compiler when compiling the first snippet is equivalent to the second snippet, which is redundant. Questions: a) Is this correct? b) If so, why is is implemented like that?

This is because I find the first snippet a lot clearer and prettier than the actually well-written

Bar y = x as Bar; if (y != null) {    something(); } 

CONCLUSION:

Optimizing the is/as case is not the compiler's responsibility, but the JIT's.

Also, as with a null check it has fewer (and less expensive) instructions than both of the alternatives (is and as and is and cast).

Addendum:

CIL for as with nullcheck (.NET 3.5):

L_0001: ldarg.1 L_0002: isinst string L_0007: stloc.0 L_0008: ldloc.0 L_0009: ldnull L_000a: ceq L_000c: stloc.1 L_000d: ldloc.1 L_000e: brtrue.s L_0019 L_0011: ldarg.0 L_0019: ret 

CIL for is and cast (.NET 3.5):

L_0001: ldarg.1 L_0002: isinst string L_0007: ldnull L_0008: cgt.un L_000a: ldc.i4.0 L_000b: ceq L_000d: stloc.1 L_000e: ldloc.1 L_000f: brtrue.s L_0021 L_0012: ldarg.1 L_0013: castclass string L_0018: stloc.0 L_0019: ldarg.0 L_0021: ret 

CIL for is and as (.NET 3.5):

L_0001: ldarg.1 L_0002: isinst string L_0007: ldnull L_0008: cgt.un L_000a: ldc.i4.0 L_000b: ceq L_000d: stloc.1 L_000e: ldloc.1 L_000f: brtrue.s L_0021 L_0012: ldarg.1 L_0013: isinst string L_0018: stloc.0 L_0019: ldarg.0 L_0021: ret 

These have been edited for shortness (method declarations, nops and calls to something() removed).

like image 922
Vinko Vrsalovic Avatar asked Feb 12 '10 11:02

Vinko Vrsalovic


People also ask

Why implement is used for?

The implements keyword is used to implement an interface . The interface keyword is used to declare a special type of class that only contains abstract methods. To access the interface methods, the interface must be "implemented" (kinda like inherited) by another class with the implements keyword (instead of extends ).

What does implementation mean?

Means of implementation (MoI) describes the interdependent mix of financial resources, technology development and transfer, capacity‐building, inclusive and equitable globalization and trade, regional integration, as well as the creation of a national enabling environment required to implement the sustainable ...

What is the another word of implement?

Some common synonyms of implement are appliance, instrument, tool, and utensil. While all these words mean "a relatively simple device for performing work," implement may apply to anything necessary to perform a task. crude stone implements. farm implements.

What is example of implement?

An example of implement is a manager enforcing a new set of procedures. A tool or instrument for working with. They carried an assortment of gardening implements in the truck. A tool, utensil, or other piece of equipment used in doing work.


2 Answers

a) Is this correct

Yes, though I would have stated it the other way. You are saying that "is" is a syntactic sugar for as-followed-by-null-check. I would have said it the other way: that "as" is a syntactic sugar for "check for type implementation, cast if success, null if failure".

That is to say, I would be more inclined to say

if (x is Bar) {     Bar y = x as Bar;     something();  }  

is effectively equivalent to

if (x is Bar) {     Bar y = (x is Bar) ? (Bar)x : (Bar) null;     something();  }  

See, you want to define "as" in terms of "is", not the other way around. The question really should be "why is as implemented as is?" :-)

b) If so, why is is implemented like that?

Because that's a correct implementation of the specification.

I think I'm not following your line of thought here. Is there something wrong with that implementation? How would you prefer it to be implemented? You have the "isinst" and "castclass" instructions at your disposal; describe the codegen for your program that you'd like to see.

like image 189
Eric Lippert Avatar answered Sep 23 '22 02:09

Eric Lippert


Well, the IL instruction that is available (isinst) will return either an object of the appropriate type, or null if such a conversion is not possible. And it doesn't throw an exception if the conversion isn't possible.

Given that, both "is" and "as" are trivial to implement. I wouldn't claim that "is" is implemented as "as" in this case, just that the underlying IL instruction allows both to occur. Now, why the compiler isn't able to optimize the "is" followed by "as" into a single isinst call, that's another matter. Probably, in this case, it's related to variable scope (even though by the time this is IL, scope doesn't really exist)

Edit

On second thoughts, you can't optimise "is" followed by "as" into a single isinst call, without knowing that the variable under discussion isn't subject to update from other threads.

Assuming x is a string:

//Thread1 if(x is string)  //Thread2 x = new ComplexObject();  //Thread1     y = x as string 

Here, y should be null.

like image 26
Damien_The_Unbeliever Avatar answered Sep 21 '22 02:09

Damien_The_Unbeliever