# 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.

Tags

1. Brian says:

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".

– Eric

2. Simon Buchan says:

@Brian: it means that "if (foo is Bar) { UseBar((Bar)foo); } has no worse performance than "var bar = foo as Bar; if (bar != null) { UseBar(bar); }", which is good to know, I can feel good about using the pretty code.

3. Brian says:

@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.

4. VMykyt says:

Do you mean "bool b = (x as Foo) != null" ?

%)

Was a typo. Corrected. Thanks! – Eric

5. Paul says:

> 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! – Eric

6. carlos says:

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.

7. Kevin Stevens says:

8. OmariO says:

"is is is, and as is as is is"

Sharpnglish 🙂

9. Robert Hahn says:

8 posts and no obvious Clinton jokes?  Maybe if you made this a programming challenge there's be more traction 🙂

10. LBushkin says:

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. – Eric

11. Diego F. says:

@Brian

Some people actually write code where computations are the bottleneck. See scientific and financial community for example. Every instruction counts and using the right language features in the right place can avoid  the need to go for low-level languages like C, or having to do some crazy interop.

@Eric

Do you recommend any good book or resource that goes deeply into the CLR and IL?

12. Daniel says:

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?

13. Mark Knell says:

Here's a vote for continued fabulousness without fabulation.  Leave the pizzazz as is.

14. While I 100% agree with rite clean code, and look at performance when there is a measurement (against a specification) that warrants it…it still drives me nuts to see:

if (myObj is MyClass)

{

MyClass myClass = myObj as MyClass;

myClass.Method();

}

Unfortunately I run into it in code far too often….

15. Brian says:

@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.

16. Rohan Singh says:

That should be default(Foo), not (Foo)null, right?

🙂

17. Rohan Singh says:

@Rohan Singh: Ah, never mind, somehow never realized that as doesn't work with value types.

18. Kelly D says:

@David V,

so if I need to test if myObj is a MyClass, and if so, then cast myClass as a MyClass and set it equal to myObj, then what is the better, dont-drive-an-mvp-nuts way of doing it?

19. Michael Liu says:

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).

20. Harry Steinhilber says:

@Kelly D,

MyClass myClass = myObj as MyClass;

if (myClass != null)

{

myClass.Method();

}

21. Michael Liu says:

Um, ignore the nonsensical "(at least for value types)"…

22. AC says:

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.

23. Siderite says:

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.

24. Matthew Jones says:

> I now invite you to leave the obvious jokes about President Clinton in the comments.

Huh?  Forgive me, but this went over my head a little.  Perhaps I missed something as I'm not a US resident…

25. Anthony P says:

@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."

26. Anthony P says:

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."

27. Tim Goodman says:

Was there a reason to use temp as opposed to just

Foo f = (x is Foo) ? (Foo)x : (Foo)null;

What if "x" is "X()" and it returns a Foo? You don't want it to be called twice. – Eric

28. John M. says:

Hi Eric, yet another fabolous post!

I do prefer using 'as' on reference types and thanks to fxCop, so does my team:)

29. Daniel Smith says:

If it is as if it is so, so be it 🙂

30. Steve Hiner says:

What was was before was was was?

Before was was was, was was is!

31. Slavo says:

What's the purpose of casting null to Foo in the last code example?

32. Bent Rasmussen says:

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…

33. Lucero says:

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.

34. Tameem Zaaiter says:

by the way …. so romantic title for the article

35. salvis says:

Various posters have already pointed this out and shown a number of variants: C# code is riddled with clumsy constructs like

Foo f = x as Foo;
if ( x != null )
x.DoSomething();

and

if ( x is Foo )
((Foo) x).DoSomething();

C# simply doesn't have any good syntax for this. C++ offers the following elegant and well-defined construct (translated to C#):

if ( var f = x as Foo )
f.DoSomething();

The C++ Standard interprets it as follows: "The value of a condition that is an initialized declaration […] is the value of the declared variable implicitly converted to type bool."

C# does not have such implicit conversions, but if we restrict the type (Foo) to being a reference type, then the condition could be defined strictly as whether the variable (f) is non-null. This would also be useful in constructs like

if ( var item = dictionary[key] )
item.DoSomething();

Support for defining references in if-statements would eliminate a lot of tedious and distracting null comparisons, and it has the advantage of automatically restricting the scope of the variable to where it is useful.