Is is as or is as is?
Today a question about the is and as operators: is the is operator implemented as a syntactic sugar for the as operator, or is the as operator implemented as a syntactic sugar for the is operator? More briefly, is is as or is as is?
Perhaps some sample code would be more clear. This code
bool b = x is Foo;
could be considered as a syntactic sugar for
bool b = (x as Foo) != null;
in which case is is a syntactic sugar for as. Similarly,
Foo f = x as Foo;
could be considered to be a syntactic sugar for
var temp = x;
Foo f = (temp is Foo) ? (Foo)temp : (Foo)null;
in which case as is a syntactic sugar for is. Clearly we cannot have both of these be sugars because then we have an infinite regress!
The specification is clear on this point; as (in the non-dynamic case) is defined as a syntactic sugar for is.
However, in practice the CLR provides us instruction isinst, which ironically acts like as. Therefore we have an instruction which implements the semantics of as pretty well, from which we can build an implementation of is. In short, de jure is is is, and as is as is is, but de facto is is as and as is isinst.
I now invite you to leave the obvious jokes about President Clinton in the comments.
Comments
Anonymous
September 15, 2010
This is interesting. However, why should I, as a programmer who wants to get things done, actually care? I reject the premise of the question; I'm not saying that you or anyone else should care about this specification/implementation detail. I don't understand what moral questions about what you should and should not care about come into it. To clarify: the question seems predicated on the syllogism: "Eric writes about things that are important for developers to understand; Eric wrote about the relationship between the is and as operators; therefore Eric thinks that knowing this relationship is important." Were that the case then it would be reasonable to ask why I think this is important, but it is not the case. That syllogism is based on a first premise which is false, and therefore the conclusion does not follow. I do not necessarily write about things that are important for developers to understand; I write about things that are fabulous! And the person who gets to decide what is fabulous is me. If some of those fabulous things happen to be important, that's super, but that's not my aim. The name of the blog is not "Important Stuff You Should Know About Coding". - EricAnonymous
September 15, 2010
The comment has been removedAnonymous
September 15, 2010
@Simon: I'll use pretty code regardless and totally and deliberately ignore any possible differences until my code has performance problems, at which point I'll use a profiler. I think it highly unlikely that this type of syntactic sugar will be the bottleneck, and think that if the bottleneck is something this low level, then I probably have bigger concerns. So, I don't really consider efficiency to be a reason to care. At profiling point of something that low level I'd be apt to be trying both regardless, checking the spec, or examining the IL.Anonymous
September 15, 2010
The comment has been removedAnonymous
September 15, 2010
> isinst, which returns a bool I think you're wrong - AFAICT the CIL instruction isinst actually acts like the "as" operator (i.e. it returns the instance unmodified if the type-check passes or null otherwise). See ECMA-335 partition III section 4.6. You are correct and I am WRONG WRONG WRONG. I was misremembering the codegen. I've updated the text. Thanks! - EricAnonymous
September 15, 2010
Paul is right. "isinst" works like "as". To save anyone else looking up the text: The isinst instruction tests whether obj (type O) is an instance of class. class is a metadata token (a typeref, typedef or typespecsee Partition II) indicating the desired class. If the class of the object on the top of the stack implements class (if class is an interface) or is a derived class of class (if class is a regular class), or if class is System.Nullable<T> and the object’s class is of type T, then it is cast to the type class and the result is pushed on the stack, exactly as though castclass had been called. Otherwise null is pushed on the stack. If obj is null, isinst returns null.Anonymous
September 15, 2010
Personally, I think this entire post is about covering your as.Anonymous
September 16, 2010
"is is is, and as is as is is" Sharpnglish :)Anonymous
September 16, 2010
8 posts and no obvious Clinton jokes? Maybe if you made this a programming challenge there's be more traction :)Anonymous
September 16, 2010
Doesn't the compiler also perform static analysis on the expression and elide the codegen entirely if the result is known at compile time? For example: bool b = 5 is int; // or ... string s = "abc" as string; can be determined entirely statically. Yes, those are codegen'd as though they were constants. The compiler should produce a warning in such cases. This strategy has caused some bugs over the years where the C# and CLR rules are slightly different: see this post for details. Introducing variant conversions in C# 4 also caused some bugs in this optimization. - EricAnonymous
September 16, 2010
The comment has been removedAnonymous
September 16, 2010
Does anyone anywhere program in actual MSIL? If I were to want to do that (for some unknown and maybe unknowable reason), suggestions on how to get started?Anonymous
September 16, 2010
Here's a vote for continued fabulousness without fabulation. Leave the pizzazz as is.Anonymous
September 16, 2010
The comment has been removedAnonymous
September 16, 2010
@Diego: Fair enough. Perhaps my response is too personalized to be a contribution to this discussion. @Eric: I was more interested in an answer to the question "Is knowing the answer to this question important to programmers who want to get things done important? If so, when?" Simon/Diego discussed one such answer.Anonymous
September 16, 2010
The comment has been removedAnonymous
September 16, 2010
@Rohan Singh: Ah, never mind, somehow never realized that as doesn't work with value types.Anonymous
September 16, 2010
The comment has been removedAnonymous
September 16, 2010
Because "is" can be used with both references types and value types but "as" can only be used with reference types, "as" must be defined in terms of "is" (at least for value types).Anonymous
September 16, 2010
@Kelly D, MyClass myClass = myObj as MyClass; if (myClass != null) { myClass.Method(); }Anonymous
September 16, 2010
Um, ignore the nonsensical "(at least for value types)"...Anonymous
September 16, 2010
As if my opinion counts, and I don't want a style war, but ... I've preferred to us 'is' only when I don't use the value in the method. If I'm using the value, I use 'as' much like @Harry above. It just seems redundant otherwise. I make the decision regardless, and I make the cast regardless. In practice, we rarely use 'is', but it's still a nice syntactic sugar nonetheless.Anonymous
September 16, 2010
I've read a zillion articles telling me that "is" is running a cast in the background so doing an "is" and then a cast would cause two casts when only one is required. This led me to using safe casting to set a variable, then check if it is null. I will need the variable later anyways. The problem occurs with value types, where I am forced to use "is" and then do a cast. This is the only thing that bothers me about it.Anonymous
September 16, 2010
The comment has been removedAnonymous
September 16, 2010
@Matthew Jones, it was during the Clinton/Monica Lewinsky scandal about whether he did or did not lie under oath. I believe it was in a video deposition that President Clinton said something to like "it depends on that the definition of is is."Anonymous
September 16, 2010
Good grief, I can't t ype for squat this morning. ...Pres. Clinton said something like "it depends on what the definition of is is."Anonymous
September 18, 2010
The comment has been removedAnonymous
September 20, 2010
Hi Eric, yet another fabolous post! I do prefer using 'as' on reference types and thanks to fxCop, so does my team:)Anonymous
September 20, 2010
If it is as if it is so, so be it :-)Anonymous
September 22, 2010
What was was before was was was? Before was was was, was was is!Anonymous
September 28, 2010
The comment has been removedAnonymous
October 02, 2010
@David: in the world of impossible hypotheticals, how about this neat little syntactic transformation try (myObj as MyClass) { myObj.Method() .... } the actual keyword (try) is not so important; more important is that in the try scope, myObj would be typed as MyClass and would only enter if myObj is MyClass and it wouldn't be possible to use the syntax var x as T because that would still let you use something that is null. Correct by construction would be nice, but that's for a parallel universe... If I remember correctly, in Cw there is a nice null propagation semantics so maybe you can do something like myObj.Method() without null fear (with "null" fear?).. maybe not...Anonymous
October 03, 2010
In the past I have also wished for something like Bent's suggestion, but I would make it more general/universal by inferencing the type of local variables as long as this is safely possible: var x = Whatever(); if (x is IDisposable) { x.Dispose(); // the compiler knows that x is a IDisposable here } x.Dispose() // compiler error here, x may not be a IDisposable This would make local variables behave more like variable of a generic type argument with constraints, where the compiler also "knows" hat the constrained type will be of a specific class and implement some specific interfaces, so that those methods can be called without requiring a cast.Anonymous
October 05, 2010
by the way .... so romantic title for the articleAnonymous
October 20, 2010
The comment has been removed