Scott Hanselman

The Weekly Source Code 10 - Patterns Considered Harmful

October 30, 2007 Comment on this post [15] Posted in ASP.NET | Microsoft | Source Code
Sponsored By

In my new ongoing quest to read source code to be a better developer, I now present the tenth in an infinite number of a weekly series called "The Weekly Source Code." Here's some source I'm reading this week that I enjoyed.

Our theme this week is "Patterns Considered Harmful" with examples of source doing things we're "not supposed to do."

  • ÜberUtils - Strings from Brad Vincent. Don't like System.String? Well, spot-weld a bunch of useful stuff onto it with C# 3.0 Extension Methods. Brad starts to talk about how his utils might be Considered Harmful:

    "Now I know some people might argue that this is extension method abuse, but look at how much more power my strings have...and anything that helps me code quicker and smarter is not abuse in my book - it's smart coding!"

    Here's just two of his many useful additions you can hardly consider harmful:
            public static string XOR(string input, string strKey)
            {
                if (IsEmpty(input)) return input;
                string strEncoded = string.Empty;
                int nKeyIndex = 0;
                for (int i = 0; i < input.Length; i++)
                {
                    strEncoded += Convert.ToChar(input[i] ^ strKey[nKeyIndex]);
                    nKeyIndex++;
                    if (nKeyIndex == strKey.Length) nKeyIndex = 0;
                }
                return strEncoded;
            }
    
            public static string ToTitleCase(string Input)
            {
                return System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(Input);
            }
  • This item isn't source, but rather a study topic. I saw that Jeff Atwood had a recent post on "Considered Harmful" docs and mentions the seminal GOTO considered harmful paper. Take a free moment and go read the interesting January 2003 thread of discussion between a number of programmers and Linus Torvalds, creator of Linux about Linus's use of GOTO in the Linux Kernel. Why? Here's a teaser from Linus:

    "No, you've been brainwashed by CS people who thought that Niklaus Wirth (Editor: Author of GOTOs Considered Harmful) actually knew what he was talking about. He didn't. He doesn't have a frigging clue."

    > I thought Edsger Dijkstra coined the "gotos are evil" bit in his
    > structured programming push?

    Yeah, he did, but he's dead, and we shouldn't talk ill of the dead. So these days I can only rant about Niklaus Wirth, who took the "structured programming" thing and enforced it in his languages (Pascal and Modula-2), and thus forced his evil on untold generations of poor CS students who had to learn langauges that weren't actually useful for real work.
    - Linus

  • Putting everything all on one line. I'll do a separate post on this, but Lee Holmes (author of the Windows PowerShell Cookbook) and I were doing some PowerShell recently, parsing CSV files and did this. Lee doesn't recommend it, but I think it's pretty:
  • Import-CSv File.csv | Select File,Hits | Group { $_.File -replace '/hanselminutes_(\d+).*','$1' } | Select Name,{ ($_.Group | Measure-Object -Sum Hits).Sum }

Feel free to send me links to cool source that you find hasn't been given a good read.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

November 8th - Seattle/Redmond/Bellevue Nerd Dinner

October 28, 2007 Comment on this post [26] Posted in ASP.NET | Microsoft | Musings
Sponsored By

blogging Are you in King County/Seattle/Redmond/Bellevue and surrounding areas? Are you a huge nerd? Perhaps a geek? No? Maybe a spaz, dork, dweeb or wonk. Maybe you're in town for an SDR (Software Design Review) or the PNP Summit. Quite possibly you're just a normal person.

Regardless, why not join us for some Mall Food at the Crossroads Bellevue Mall Food Court on November 8th around 6:30pm? You can even help me write my speech that I have to give that Friday. ;)

Here's some links to help you remember and add this to your calendar:

Feel free to RSVP in the comments. If you want to come and share something with the group, please do! We're language and technology agnostic and always eager to learn about new stuff.

I've only been at Microsoft 7 weeks now and it'd be great if more Microsoft people came - everyone loves to put a face to a blog and sometimes Microsoft folks get tunnel vision and don't learn about what's going on in other groups! Blue Badges welcome...Please spread the word!

Hope to see you there. If not, I shall eat my Spicy Chicken alone in peace.

UPDATE: You might also want to check out the Seattle Code Camp this November 17 and 18th. You can register here. For some reason there's a certificate error on their site, looks like a problem with their SSL.  I know the guys who run it, so I wouldn't worry about the error, I'm sure it'll be fixed soon.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Hanselminutes Podcast 86 - Open Source Software Licensing with Jonathan Zuck of ACT Online

October 28, 2007 Comment on this post [14] Posted in ASP.NET | Musings | Podcast | Source Code
Sponsored By

3271123971My eighty-sixth podcast is up. In this one we turn to Jonathan Zuck, President of the Association for Competitive Technology to demystify Software Licensing and the industry's many Open Source Software Licenses. Jonathan also talks about their Innovators Network and what it can do for entrepreneurs.

Subscribe: Subscribe to Hanselminutes Subscribe to my Podcast in iTunes

If you have trouble downloading, or your download is slow, do try the torrent with µtorrent or another BitTorrent Downloader.

Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

Telerik is our sponsor for this show.

Check out their UI Suite of controls for ASP.NET. It's very hardcore stuff. One of the things I appreciate about Telerik is their commitment to completeness. For example, they have a page about their Right-to-Left support while some vendors have zero support, or don't bother testing. They also are committed to XHTML compliance and publish their roadmap. It's nice when your controls vendor is very transparent.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Release IS NOT Debug: 64bit Optimizations and C# Method Inlining in Release Build Call Stacks

October 25, 2007 Comment on this post [14] Posted in ASP.NET | Learning .NET | Microsoft | Programming
Sponsored By

Just a reminder: Release builds are not Debug builds. Seems obvious, but it's worth saying again. Release builds are optimized for speed and debug builds are optimized for, well, debug-ability. However, most of the optimizations in managed code are done by the JIT compiler rather than the language compiler.

However, sometimes in our zealous attempts to make Release builds easier to debug we can inadvertently (or totally "vertently") remove a lot of the optimizations that make Release builds faster.

Introduction

I was talking to Jeremy and he had come upon some code that was inserting a try{} catch() { throw; } block in every method. The rationale was that "they wanted the complete stack trace in their logging after an exception was thrown." That's a noble goal, but their technique of adding these guards is what's called an "anti-pattern" or as Egon would say "it would be bad." An anti-pattern is "a pattern that tells how to go from a problem to a bad solution."

First, let's start by exploring why they aren't getting "a complete stack trace" before we tackle why they believe they want/need a complete one.

Here's a simple program:

using System;

class NormalProgram
{
    static void Main(string[] args)
    {
        try
        {
            methodA();
        }
        catch (System.Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    static void methodA() { methodB(); }
    static void methodB() { methodC(); }
    static void methodC() { badMethod(); }
    static void badMethod() { throw new ApplicationException("generic bad thing"); }
}

In this program, Main calls A, then A calls B, which calls C, which calls badMethod which throws an exception. That exception is caught up at Main. So far, makes sense right?

We'll compile two versions, one in Debug mode and one in Release and run them on a regular 32-bit machine. Notice we're saying /o for enable optimizations for the Release build. We are making debug symbols for Release via /debug:pdbonly, but it doesn't affect performance in a significant way.

"%FXROOT%\csc.exe" /t:exe /out:NormalRelease.exe /debug:pdbonly /o NormalProgram.cs
"%FXROOT%\csc.exe" /t:exe /out:NormalDebug.exe /debug NormalProgram.cs

We run Debug on 32-bit and we see:

System.ApplicationException: generic bad thing
   at NormalProgram.badMethod() in NormalProgram.cs:line 24
   at NormalProgram.methodC() in NormalProgram.cs:line 23
   at NormalProgram.methodB() in NormalProgram.cs:line 21
   at NormalProgram.methodA() in NormalProgram.cs:line 19
   at NormalProgram.Main(String[] args) in NormalProgram.cs:line 11

Looks good, makes sense. Now we run Release on 32-bit:

System.ApplicationException: generic bad thing
   at NormalProgram.badMethod() in NormalProgram.cs:line 24
   at NormalProgram.Main(String[] args) in NormalProgram.cs:line 11

Our call stack has been "collapsed"? Does it make it harder to debug? Not really, because we knew where we ended up and the path between the two is clear (otherwise this "inlining" wouldn't have happened.)

However, it is confusing and there's a perception that "information is missing." It's important to note that information isn't missing but rather this stack trace is showing the runtime reality. What you write (the Programmer's Intent) isn't exactly what runs, especially when things are optimized. As programmers we are doing our best to tell the machine what to do and it is doing its best to do that fast and correct - let it do what it does best. When we see a stack like this our first reaction is that information is there, but has been hidden. In fact, the code we wrote ran, but not every method got their own local stack frame as they were optimized into fewer methods.

Inlining

Disclaimer: I'm showing you this for informational purposes. Doing this without thinking or having a good reason is usually  a bad idea and could confuse other issues. The only reason you might want to do this would be if you were doing some kind of funky thing that made your method require its own stack space. DON'T ADD THIS ATTRIBUTE WILLY-NILLY. Don't Program By Coincidence. Remember the point of this post is that Release and Debug are different. Use them differently.

What if I tell the runtime JIT-ter to not inline? I'll add one line and one using:

using System;
using System.Runtime.CompilerServices;

class NormalProgram
{
    static void Main(string[] args)
    {
        try
        {
            methodA();
        }
        catch (System.Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    static void methodA() { methodB(); }
    static void methodB() { methodC(); }
    static void methodC() { badMethod(); }
    static void badMethod() { throw new ApplicationException("generic bad thing"); }
}

And run on 32-bit:

System.ApplicationException: generic bad thing
   at NormalProgram.badMethod() in NormalProgram.cs:line 24
   at NormalProgram.methodA() in NormalProgram.cs:line 19
   at NormalProgram.Main(String[] args) in NormalProgram.cs:line 11

Well, that stopped the inlining of method A, but of course B and C are still inlined. You can see how this is going to get icky.

ASIDE: We as programmers have all reached this moment. This is the moment when we decide whether or not to slap an attribute on every method in our program. (This attribute is just an example, but you know this moment...there's still time to actually stop and try to understand the problem...)

...but we have to ship. So, let's try this:

using System;
using System.Runtime.CompilerServices;

class NormalProgram
{
    [MethodImpl(MethodImplOptions.NoInlining)] 
    static void Main(string[] args)
    {
        try
        {
            methodA();
        }
        catch (System.Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    static void methodA() { methodB(); }
    [MethodImpl(MethodImplOptions.NoInlining)] 
static void methodB() { methodC(); } [MethodImpl(MethodImplOptions.NoInlining)] static void methodC() { badMethod(); } static void badMethod() { throw new ApplicationException("generic bad thing"); } }

And compile and run as Release on 32-bit...

System.ApplicationException: generic bad thing
   at NormalProgram.badMethod() in NormalProgram.cs:line 24
   at NormalProgram.methodC() in NormalProgram.cs:line 23
   at NormalProgram.methodB() in NormalProgram.cs:line 21
   at NormalProgram.methodA() in NormalProgram.cs:line 19
   at NormalProgram.Main(String[] args) in NormalProgram.cs:line 11

Now we're back where we were before, right? Well, not really. We've got the full stack again, but we've neutered the build such that the JITter can't really do it's job.

Plus, we haven't tried 64-bit yet. Let's run the Release build on 64-bit:

System.ApplicationException: generic bad thing
   at NormalProgram.methodC() in NormalProgram.cs:line 23
   at NormalProgram.Main(String[] args) in NormalProgram.cs:line 11

Weird. One conclusion to draw would be that 64-bit CLR ignores method inlining attributes. That's not necessarily the case. Another would be that 64-CLR is more aggressive about inlining. The deal is that there are MANY optimizations that the JITter can to. MANY. They wouldn't give me a number because it's Special Sauce, but le's just say it's not one or two. It's more than that. ;)

Inlining isn't the only thing that can "collapse" a call stack like this. This also isn't exactly true. In this case, remember that x64 is a whole new processor architecture while x86 has been around for, let's say, a while. Turns out that x64 really likes to optimize and this is an example of a "Tail Call Optimization" rather than explicit Method Inlining.

Be sure to read David Broman's detailed blog post on exactly x64 tail-call optimizes and when it doesn't.

A good explanation from The Original Wiki at the Portland Pattern Wiki:

"Tail-call optimization (or tail-call merging or tail-call elimination) is a generalization of TailRecursion: If the last thing a routine does before it returns is call another routine, rather than doing a jump-and-add-stack-frame immediately followed by a pop-stack-frame-and-return-to-caller, it should be safe to simply jump to the start of the second routine, letting it re-use the first routine's stack frame (environment)...."

"However, TailCallOptimization has some drawbacks. The runtime environment will have a confusing stack during execution of tail-called routines, which can make debugging difficult ("How did I get here? baz() never even calls foo()!")."

The wiki explanation was written with C in mind, but the concept is universal and it's the "confusing stack during execution of tail-called routines" that's got me writing this blog post today.

There's some controversy on whether Tail Call Optimizations are a subset of Method Inlining. That may never be resolved, but for now they are discrete and different. Eric Gunnerson has a good article on some of the heuristics that the JIT uses in its inlining decision making process.

For some hardcore details, be sure to read David Notario's excellent series on x86 JIT inlining from 2004, both Part 1 and Part 2. Perhaps start by reading his "The CLR x86 JIT, an overview" as he explains seven basic stages the x86JIT.

An Anti-Pattern

Now, back to our customer from the beginning who was inserting a try{} catch() { throw; } block in every method. Let's try that (don't do this at home):

using System;

class UglyProgram
{
    static void Main(string[] args)
    {
        try
        {
            methodA();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);                
        }
    }
    static void methodA() { try { methodB(); } catch { throw; } }
    static void methodB() { try { methodC(); } catch { throw; } }
    static void methodC() { try { badMethod(); } catch { throw; } }
    static void badMethod(){throw new ApplicationException("generic bad thing");}
}

...and compile both Debug and Release and this produces the same output on both 32-bit and 64-bit:

System.ApplicationException: generic bad thing
   at UglyProgram.badMethod() in UglyProgram.cs:line 20
   at UglyProgram.methodC() in UglyProgram.cs:line 19
   at UglyProgram.methodB() in UglyProgram.cs:line 18
   at UglyProgram.methodA() in UglyProgram.cs:line 17
   at UglyProgram.Main(String[] args) in UglyProgram.cs:line 10

Why? Because by setting up the try's you're introducing the potential for other ways out of each method so the JIT'ter can't optimize anything that would collapse the call stack like we saw earlier. This isn't a good pattern as it doesn't deal with the underlying issue in a simple way. The customer wants to be able to debug Release builds easier.

Options

Here's some options we could try:

  • Try/catch every method - Not a good idea. Not only are you cluttering your code, but you're paying a cost all the time when you only need to debug in Production/Release occasionally.
  • Put [MethodImpl(MethodImplOptions.NoInlining)] on every method - Also not a good idea, not only because of the operative "every method" violating the DRY Principle but also because it only deals with one specific optimization out of many.
  • Turn off Optimizations in the compiler - This particular kind of inlining appears to be a JITter thing, not a language compiler thing so turns out that doesn't work in this instance.

Ok, so the customer wants a fuller call stack. I would propose that they in fact don't want this. One of my old bosses used to say:

"Customer walks in with a cell phone and says 'this thing needs a bigger antenna.' We have to ask ourselves does he want a bigger antenna or better cell phone reception" - Mark Klein

This is a great pithy analogy. Everyone comes in with both Problems and Solutions. This customer wants to be able to debug Release builds. They surely don't want full call stacks in Release Mode if it means turning off all optimizations.

Best Solution

One thing the customer could do that would give them the best of both worlds is something Mark Pearce told me about a while back, the [.NET Framework Debugging Control] section of an .ini file you've probably never used:

This JIT configuration has two aspects:

  • You can request the JIT-compiler to generate tracking information. This makes it possible for the debugger to match up a chain of MSIL with its machine code counterpart, and to track where local variables and function arguments are stored.
  • You can request the JIT-compiler to not optimize the resulting machine code.

If you have a file Foo.exe you can create a Foo.ini with these contents:

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0

Implementation Detail: Why is it an INI file? Well, the .NET runtime hasn't started up yet, so we don't have all that XML-parsey goodness lying around. Instead they need to use the Win32 method GetPrivateProfileString() in order to retrieve those.

This solution assumes you compiled with /debug:pdbonly in Release mode in order to generate the full stack when needed.

DICSLAIMER: This isn't something you want to put into production! You'd only use this for debugging. It's something you'd enable on a case-by-case basis.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

How to easily disable Reply To All and Forward in Outlook

October 24, 2007 Comment on this post [40] Posted in Musings | Programming | Tools
Sponsored By

2010 UPDATE: This is cool and interesting to read, but you should just go get this Free Outlook 2007/2010 No Reply All AddIn to do this work for you.

UPDATE: To be clear. This technique does NOT send macros in your email. It only flips a metadata bit in the message and that metadata is only transmitted within Exchange (within your company). It is not propagated to outside email addresses. It's better than BCC because it doesn't break local Outlook Rules. It's harmless.

I really hate it when I say "please send replies directly to me" and a Reply To All happens. It's not only a bummer for the person who sent it but also for everyone on the distribution list.

Trivia: At Microsoft they/we say "little-r" me when we want a reply directly to us or "Big-R" when we mean Reply To All.

I was thinking it'd be cool to have a button on my Outlook Message Form that prevented folks from Reply'ing to All or Forwarding the message. I poked around a bit trying to write an Outlook Macro and realized that I've completely overwritten all the brain cells that had previously held information about VBA macro programming. Seriously. I worked in VB3-6 for years. I was a ninja. Now I'm just an old fat guy with a Black Belt that used to fit. Anyway.

I asked for help and KC Lemson pointed me to Bill Jacob, both actual ninjas, and he took my Rube Goldberg-ian plan and turned it into two lines of code. Doh.

Here's "How to easily disable Reply To All and Forward in Outlook":

Go Tools|Macro|Macros...

image

In the next dialog, type something like NoReplyAll and click Create.

image

At this point, even when running Vista 64, you'll be magically transported back to 1996, completely with owner-draw non-standard gray toolbars and other bits of gray that will leak in from the past.

Add these lines to your new subroutine:

ActiveInspector.CurrentItem.Actions("Reply to All").Enabled = False
ActiveInspector.CurrentItem.Actions("Forward").Enabled = False

Then close this window.

image

At this point you've got a macro that prevents Replying to All and Forwarding (at least within Outlook world. This won't prevent folks running other mail systems from Replying to All, but we're mostly focused on internal work with this tip.)

Now, open up a new Outlook Message and right click at the VERY top (assuming Outlook 2007).

image

Click More Commands...now from this dialog select "Macros" from the dropdown, select your new Macro and click Add>>.

image

If you like, click on your Macro on the right and select the Modify button and pick a nice icon for it and a Display Name. I used a "halting hand" icon:

image

Click OK and look at your Quick Access Toolbar...you've got a nice little icon there.

image

Now, CLICK that button then send an email to yourself or a coworker...

image

Cool, mission accomplished. One less thing to worry about. Thanks Bill!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.