There was a great comment on a recent post here last week where I was trying to get a Managed Plugin working with an application that insisted on its plugins being C++ DLLs with specific virtual methods implemented.
Here's the comment with my emphasis:
Great article. It would be nice to see a little less "managed snobism". Personally, I don't need to use up 100MB of my memory with a framework just to let me generate 32x32 bitmaps. So I'm grateful that the managed route is not the default. Remember, 90% of functions in .NET are just wrappers around the underlying API functions, so in effect, all they do is slow you down, while giving you convenience.
This reminded me of an article I did a few years ago when folks were still asking silly questions like "Is your application Pure .NET?" The article was called The Myth of .NET Purity and was published up on MSDN under an article series called ".NET in the Real World." To this day I'm still surprised that they let me publish it.
The (interestingly anonymous) commenter says: "...so in effect, all they do is slow you down, while giving you convenience." Well, sure. Everyone knows this quote:
Any problem in Computer Science can be solved with another layer of indirection.
It's a great quote. As an aside, the quote is attributed to nearly every smart Computer Scientist. Including David Wheeler, Butler Lampson and Steven M. Bellovin. Lampson says it was Wheeler, but it was one of these three guys.
But a game developer at Sun adds a clever touché to the old adage:
The two software problems that can never be solved by adding another layer of indirection are that of providing adequate performance or minimal resource usage. - Jeff Kesselman
And he's right. Of course, .NET is a (most excellent layer of) Managed Spackle over the Win32 API. But it's really GOOD spackle. It's so good that we get collectively frustrated when a new API (SideShow, AzMan) doesn't have a good initial managed API (SideShow does now). A nice, clean managed API adds a fantastic amount of convenience in exchange for a very reasonable performance hit.
The performance hit - which I haven't personally measured - is no doubt less than even the most trivial of network calls. How much overhead is added? Not much.
Approximate overhead for a platform invoke call: 10 machine instructions (on an x86 processor)
Approximate overhead for a COM interop call: 50 machine instructions (on an x86 processor)
Gosh, that isn't much. Sure, there are always scenarios we conceive of that could add up, but that's what profiling on a case-by-case basis is for.
If .NET Purity is a myth, and the whole thing is just there to make our lives easier, then this is an easy trade off. I just remember that I can code in C#/VB.NET, for a small cost. I get speed of dev, and I give up speed of execution. I can code in C++, and give up speed of dev (a smidge) and gain (possibly) speed of execution. I can code in ASM and give up lots of productivity in exchange for my immortal soul and a really fast program. Or I can go to heaven, pursue beauty if I like, and give up so much performance to cause a scandal.
But it's not a simple trade off. Certainly not at the method or even component level. William Caputo makes a similar point with emphasis mine:
...this calculation is done unconsciously by those programmers who hear "we're trading efficiency for productivity." It's why they are reluctant to take a serious look at higher-level languages. A one-time productivity hit to get faster run-time performance certainly seems like a good trade-off, but the flaw in the argument is that productivity measurement is not reset with each task. It's cumulative. Unlike a programming assignment ("Implement Quick Sort Please"), productivity is measured across an entire solution (whether a build script or a trading system) -- and not just the first writing of the code, but throughout its useful lifetime (the vast majority of coding time is spent changing, or maintaining existing code).
In the real world, its not "write once, run forever", its "write a bit, run a bit, change a bit, run a bit", and so on. I am not saying that run-time efficiency isn't important. It is. The best way to compare run-time efficiency and programmer productivity is not at the micro level, but at the macro level.
Yes, .NET adds overhead. Certainly not enough to worry about for business apps, given the productivity gains. We're not writing device drivers here. In my original example where I want to write managed plugins for the Optimus Keyboard, since the max frames per second on the keyboard is 3fps, performance isn't a concern (nor would it be even if I needed 30fps).
If being a Managed Code Snob is wrong, I don't wanna be right.