relative cost of is versus as

  • Thread starter Thread starter Rob S
  • Start date Start date
R

Rob S

I'm new to C#, new to a project, and wondering about the differences
between two ways of handling a particular situation in our code. In a
nutshell, what is the performance difference between "is" and "as"
operations?

Basically, we have an event that is triggered each time a sub object is
added to a parent object - call it SuperWidget. By its nature, single
instances of some types of subobjects are added (SuperWidgetHeader,
SuperWidgetFooter, etc.), and multiple instances of another type of
object are added (SuperWidgetWidget). The number of SuperWidgetWidgets
may vary from say 4 to 45, so this event gets triggered from less than
10 to almost 50 times, depending upon the particular instance of
SuperWidget. (There may end up being dozens so SuperWidgets created
and destroyed throughout the day.)

We need to do some special handling for the SuperWidgetHeader, so in
the event handler we're using something like:

SuperWidgetHeader playObject = sourceObject as SuperWidgetHeader;
if (null != playObject) then
{
playObject.SomeMethod()
...
From a readability standpoint, I think this is preferable:

if (sourceObject is SuperWidgetHeader)
{
SuperWidgetHeader playObject = sourceObject as SuperWidgetHeader;
playObject.SomeMethod();
...

but I'm told the first version is more efficient because the "as"
casting is less expensive than the "is" casting (not to mention in the
second version once we find the right type of object, we have to cast
it a second time). They can't point me to a reference to this though,
and I haven't been able to dig up anything, either.

Functionally, what is the difference between the two, and is the
overhead worth sacrificing for sake of readability?

For what its worth, research suggests a more efficient way to handle
this may just be something like:

if (sourceObject.ToString() == "SuperWidgetHeader")
{
SuperWidgetHeader playObject = sourceObject as SuperWidgetHeader;
playObject.SomeMethod();
...

because (depending upon how SuperWidget impliments it) ToString() may
avoid the expensive casting issues altogether, but we all seem to agree
embedding strings in the code for comparison purposes runs counter to
the whole object philosophy, so we're pretty much rejecting this
approach completely. How invalid is this thinking?

At any rate, back to the original question - what's the difference
between "is" and "as"?
 
Hi Rob,
the difference between the two methods is virtually nothing. I did some
testing on this a while ago and the difference of using "as" vs "is" was 1ms
over 1,000,000 iterations - so nothing to lose any sleep over, especially the
low number you are calling, it is much more likely you will hit a performance
issue somewhere else in one of your algorithms. I posted something to an old
blog a while ago, see: http://markrdawson.blogspot.com/

In response to using strings to compare class names that just seems too open
for subtle bugs to slip into your code, best to stay away.

Also ideally in my opinion using as and is, is a kind of ugly OOP solution,
a controller type object should not need to worry about the specific concrete
type of a class, each class should know how to handle itself. You should
abstract out the functionality into an interface or abstract class and let
you SuperWidget just call into some abstraction rather than worrying about
specific concrete classes.

Mark.
 
Rob S said:
The number of SuperWidgetWidgets
may vary from say 4 to 45, so this event gets triggered from less than
10 to almost 50 times, depending upon the particular instance of
SuperWidget. (There may end up being dozens so SuperWidgets created
and destroyed throughout the day.)

So we're talking about the cost of something that happens up to about
5,000 times a *day*?
Functionally, what is the difference between the two, and is the
overhead worth sacrificing for sake of readability?

No, not for a 5000-times-a-day even that's over in a fraction of a
millisecond.


PS. I'm sorry to give a facetious answer. I don't know the real answer
to your question. I just think there's a giant collective
"can't-see-wood-for-trees" in the microsoft.csharp newsgroups when it
comes to questions of efficiency, and I snap!
 
Rob said:
I'm new to C#, new to a project, and wondering about the differences
between two ways of handling a particular situation in our code. In a
nutshell, what is the performance difference between "is" and "as"
operations?

Basically, we have an event that is triggered each time a sub object is
added to a parent object - call it SuperWidget. By its nature, single
instances of some types of subobjects are added (SuperWidgetHeader,
SuperWidgetFooter, etc.), and multiple instances of another type of
object are added (SuperWidgetWidget). The number of SuperWidgetWidgets
may vary from say 4 to 45, so this event gets triggered from less than
10 to almost 50 times, depending upon the particular instance of
SuperWidget. (There may end up being dozens so SuperWidgets created
and destroyed throughout the day.)

We need to do some special handling for the SuperWidgetHeader, so in
the event handler we're using something like:

SuperWidgetHeader playObject = sourceObject as SuperWidgetHeader;
if (null != playObject) then
{
playObject.SomeMethod()
...


if (sourceObject is SuperWidgetHeader)
{
SuperWidgetHeader playObject = sourceObject as SuperWidgetHeader;
playObject.SomeMethod();
...

but I'm told the first version is more efficient because the "as"
casting is less expensive than the "is" casting

I doubt that very much. I would be surprised if the "as" and the "is"
weren't identical in performance, since they both involve the same
thing: a cast.
(not to mention in the second version once we find the right type of object, we have to cast
it a second time).

That is the performance issue, not "as" versus "is". In one case you
cast the type once. In the other case you have to cast it twice.
Therefore, in the second case you're doing twice the work, unless the
compiler / JITter is clever enough to optimize away the second cast.

By the way, coding

if (null != playObject)

is a C++-ism. Standard C# is to code

if (playObject != null)

since C++ programmers use the back-assward way of testing variables
only because C++ will interpret integer expressions as booleans. Since
C# will not do this, there's no need to reverse the test.
 
Bruce said:
By the way, coding

if (null != playObject)

is a C++-ism. Standard C# is to code

if (playObject != null)

since C++ programmers use the back-assward way of testing variables
only because C++ will interpret integer expressions as booleans. Since
C# will not do this, there's no need to reverse the test.

Yeah, I don't like the (null != playObject) order either, but the other
members of the team appear to have C++ backgrounds (I come from VB and
Java), so I don't think they are likely going to budge on that one.

Rob
 
Mark said:
Also ideally in my opinion using as and is, is a kind of ugly OOP solution,
a controller type object should not need to worry about the specific concrete
type of a class, each class should know how to handle itself. You should
abstract out the functionality into an interface or abstract class and let
you SuperWidget just call into some abstraction rather than worrying about
specific concrete classes.

"SuperWidget" is actually a third party custom tab control, and the
mechanism the vendor created to allow access to do the sort of thing we
need to do to modify the control gives us limited options. Unless we
want to rewrite the control, we don't have a lot of options.

Rob
 
Rob said:
Yeah, I don't like the (null != playObject) order either, but the other
members of the team appear to have C++ backgrounds (I come from VB and
Java), so I don't think they are likely going to budge on that one.

As a programmer, one of the signs that you're getting old is that when
you move to a new technology or language, you bring ALL of your old
habits with you, whether they apply to the new technology / language or
not. In some cases, this is good: you bring collected experience and
understanding that greenhorns don't have. In other cases this is bad:
"I write comparisons with the constant first because I've done it that
way for ten years and, dammit, I'll do that until the day they carry me
out of here!"

Doesn't it just conjure images of old guys sitting on their rockers on
the front porch? "Young'uns these days! They don't respect any of the
old ways. They even write their comparisons with the constants
_second_!" "Nooo... you don't say! What's the world coming to?"
 
Lucian said:
So we're talking about the cost of something that happens up to about
5,000 times a *day*?

PS. I'm sorry to give a facetious answer. I don't know the real answer
to your question. I just think there's a giant collective
"can't-see-wood-for-trees" in the microsoft.csharp newsgroups when it
comes to questions of efficiency, and I snap!

Actually, this thing is a third party custom tab control, and the code
in question gets called every time the control is redrawn. That
happens a lot.

An addition, the app is basically a presentation layer for a fairly
large database system, and some clients will host it on Citrix servers
with dozens of users. On those servers, this chunk of code may run
hundreds of thousands of times a day - perhaps millions.

Also, this is merely one example of casting I've found in our code.
They seem to be doing it all over the place. It's useful to get things
done, but how expensive is it?

C# may not be the most efficient language, but it's the one I have to
deal with for this project. So, I think it's reasonable for me to
want to thoroughly understand the implications of our coding practices
- which is why I asked the question in the first place.

Rob
 
Bruce said:
As a programmer, one of the signs that you're getting old is that when
you move to a new technology or language, you bring ALL of your old
habits with you, whether they apply to the new technology / language or
not. In some cases, this is good: you bring collected experience and
understanding that greenhorns don't have. In other cases this is bad:
"I write comparisons with the constant first because I've done it that
way for ten years and, dammit, I'll do that until the day they carry me
out of here!"

Doesn't it just conjure images of old guys sitting on their rockers on
the front porch? "Young'uns these days! They don't respect any of the
old ways. They even write their comparisons with the constants
_second_!" "Nooo... you don't say! What's the world coming to?"

Actually, the real scary part here is I'm the oldest member of the
team, by several years!

Rob
 
Rob said:
Actually, the real scary part here is I'm the oldest member of the
team, by several years!

Then tell the rest of them to act their age. :-)
 
Rob S said:
Actually, this thing is a third party custom tab control, and the code
in question gets called every time the control is redrawn. That
happens a lot.

The cost of a cast will surely be insignificant next to the cost of
*DRAWING* a control. Drawing a control involves a lot of windows
messages, a lot of pixels being shifted around from place to place, a
lot of windows datastructures. Probably several transitions from
userspace to kernelspace.
 
Rob said:
I'm new to C#, new to a project, and wondering about the differences
between two ways of handling a particular situation in our code. In a
nutshell, what is the performance difference between "is" and "as"
operations?

IIRC, they're exactly the same, and "x is MyClass" generates the same
code as "(x as MyClass) != null). The real reason to prefer "as" here
is that you only have to cast once.
SuperWidgetHeader playObject = sourceObject as SuperWidgetHeader;
if (null != playObject) then
{
playObject.SomeMethod()
...


if (sourceObject is SuperWidgetHeader)
{
SuperWidgetHeader playObject = sourceObject as SuperWidgetHeader;
playObject.SomeMethod();
...

Theoretically, the CLR could notice that in the second version,
sourceObject is already guaranteed to be a SuperWidgetHeader by the
time you cast it and assign playObject. It could then skip generating
any code for the second cast, and so both versions would produce the
same code. I don't know if the CLR is currently clever enough to do
that, though.

Jesse
 
Rob said:
I'm new to C#, new to a project, and wondering about the differences
between two ways of handling a particular situation in our code. In a
nutshell, what is the performance difference between "is" and "as"
operations?

IIRC, they're exactly the same, and "x is MyClass" generates the same
code as "(x as MyClass) != null". The real reason to prefer "as" here
is that you only have to cast once.
SuperWidgetHeader playObject = sourceObject as SuperWidgetHeader;
if (null != playObject) then
{
playObject.SomeMethod()
...


if (sourceObject is SuperWidgetHeader)
{
SuperWidgetHeader playObject = sourceObject as SuperWidgetHeader;
playObject.SomeMethod();
...

Theoretically, the CLR could notice that in the second version,
sourceObject is already guaranteed to be a SuperWidgetHeader by the
time you cast it and assign playObject. It could then skip generating
any code for the second cast, and so both versions would produce the
same code. I don't know if the CLR is currently clever enough to do
that, though.

Jesse
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top