July 2004 - Posts

Language Lawyers (and Nasal Demons)

As soon as a development language has an official specification behind it, the first language lawyer appears. If you’ve never seen one in action, they are the type who can rattle off section and paragraph numbers from a specification while explaining the bizarre behavior of some code snippet. You might see them write something along the lines of:

The values of a and b are automatically promoted back to int [6.2.1.1/ 3.2.1.1], which is then the type of the result of the / operator [6.2.1.5/3.2.1.5]. Since -32768 is exactly divisible by -1, and the result of 32768 is representable in the type int, the division must yield this value.

Nearly every language with a specification will describe situations with “undefined behavior”. Undefined behavior means there is something so horribly screwed up in the code, or in the data, that the program is probably going to crash spectacularly. Except specifications never use the word ‘crash’. Many of them, including the C# spec, will use the more dignified phrase: “unpredictable results”.

Now language lawyers, not really being lawyers, have a sense of humor. Since the phrase “unpredictable results” leaves the outcome so open-ended, they will say undefined behavior could, in fact, lead to demons flying out of your nostrils.

The first apparent reference to demons and noses came in a 1992 post to the comp.std.c newsgroup. The post contains many paragraph and section number references to the C language specification, but ends with this little gem:

In short, you can't use sizeof() on a structure whose elements haven't been defined, and if you do, demons may fly out of your nose.

The phrase caught on.

In the mid 90’s I was maintaining a C code base intended for both an 8 bit Hitachi chip and the PC, so I was interested in writing portable ANSI C programs and followed the comp.std.c and comp.lang.c newsgroups. I don’t know how many times someone would come along and post code which started like this:

void main (void)

As soon as the above line appeared the language lawyers appeared in force. You could look at the code, and see it was only one semi-colon away from curing world hunger, but it didn’t matter, because the response was invariably something like:

The Standard says that declaring main as returning void invokes undefined behavior. Beware the nasal demons.

Although sometimes the lawyers would make other amusing comments:

if you write:

void main (void) 

it's *possible* (under the rules of C) that your computer will pogo round the room whistling the star spangled banner. It's very unlikely, but C isn't interested in "likely".

Whenever I was having a really bad day, I’d write a program with main returning void just to see what would happen. I tried it with the Microsoft C compiler, the Borland C compiler, the Intel C compiler, and the now defunct Boston Systems Office C compiler. I was hoping to create a horrible, slimy demon who I could train to stand at my office door and terrify people trying to enter with requirements documentation in hand. Not only did I never get a demon, the programs always worked without any errors. Shows you what the language lawyers know.

In any case, I’m hoping to find some good examples of undefined behavior in C# or VB so I can try to invoke nasal demons from .NET. I imagine it will be much harder to do with a managed runtime in place, but if you know of any opportunities, please let me know.

posted by scott with 5 Comments

Static Constructors Are Not Miracle Workers

The CLR guarantees a type initializer (static constructor) will execute only once for any given type. This simplifies my life, because I don’t need to worry about multiple threads inside of a static constructor. Take for example the following program:

static void Main(string[] args)
{
   Thread threadA = new Thread(new ThreadStart(TouchFoo));
   threadA.Name = "Thread A";
 
   Thread threadB = new Thread(new ThreadStart(TouchFoo));
   threadB.Name = "Thread B";
 
   threadA.Start();
   threadB.Start();
   
   threadA.Join();
   threadB.Join();
}
 
static void TouchFoo()
{
   Foo.SayHello();
}
 
class Foo
{
   static Foo()
   {
      Thread.Sleep(1000);
      Console.WriteLine("Foo .cctor on thread {0}", Thread.CurrentThread.Name);
   }
 
   static public void SayHello()
   {
      Console.WriteLine("Hello From Foo");
   }
}

In this program, Thread A will probably get the first chance to execute TouchFoo. In doing so, the CLR recognizes the static constructor for Foo has not been executed and sends Thread A into the constructor, which puts the thread to sleep for 1000 ms. The sleeping period allows Thread B to run. Thread B arrives inside of TouchFoo, and again the CLR recognizes the static constructor for Foo has not completed executing. This time however, the CLR knows somebody is working inside of the constructor, and it blocks Thread B until Thread A finishes Foo’s constructor. Typically then, this program would produce the following output:

Foo .cctor on thread Thread A
Hello From Foo on thread Thread A
Hello From Foo on thread Thread B

No matter how many threads we throw into the mix, the CLR will only allow one thread inside of the static constructor. Of course this isn’t magic, there has to be some thread synchronization (a lock) taken by the CLR before entering the static constructor.

Where there are locks, there is the possibility of a deadlock. So what happens if we try to put the runtime into a bind by feeding it code that should deadlock? Do you think the following program will execute, or will I need to kill it from task manager?

class Class1
{
   [STAThread]
   static void Main(string[] args)
   {
      Thread threadA = new Thread(new ThreadStart(TouchFoo));
      threadA.Name = "Thread A";
      
      Thread threadB = new Thread(new ThreadStart(TouchBar));
      threadB.Name = "Thread B";
 
      threadA.Start();
      threadB.Start();
 
      threadA.Join();
      threadB.Join();
   }
 
   static void TouchFoo()
   {
      string s = Foo.Message;
   }
 
   static void TouchBar()
   {
      string s = Bar.Message;
   }
}
 
class Foo
{
   static Foo()
   {
      Console.WriteLine("Begin Foo .cctor on thread {0}", Thread.CurrentThread.Name);
      Thread.Sleep(5000);
      Console.WriteLine("Foo has a message from Bar: {0}", Bar.Message);         
      message = "Hello From Foo";
      Console.WriteLine("Exit Foo .cctor on thread {0}", Thread.CurrentThread.Name);
   }
 
   static public string Message
   {
      get { return message; }
   }
 
   static string message = "blank";
}
 
class Bar
{
   static Bar()
   {
      Console.WriteLine("Begin Bar .cctor on thread {0}", Thread.CurrentThread.Name);
      Thread.Sleep(5000);
      Console.WriteLine("Bar has a message from Foo: {0}", Foo.Message);         
      message = "Hello From Bar";
      Console.WriteLine("Exit Bar .cctor on thread {0}", Thread.CurrentThread.Name);
   }
 
   static public string Message
   {
      get { return message; }
   }
 
   static string message = "empty";    
}

Notice in this example, the static constructor for Foo references Bar’s Message property, and vice versa. This produces the following scenario:

Thread A starts and eventually enters the static constructor for Foo. After a writing to the screen, the thread goes to sleep for 5000 ms. Thread B now has a chance to run and eventually enters the constructor for Bar, prints a message and goes to sleep.

Next, Thread A wakes up and finds it needs information from an un-initialized Bar, but it cannot run the constructor because Thread B has it locked. Thread B awakes and needs information from Foo, but it cannot run the Foo constructor because Thread A has it locked. Thread A needs the lock held by Thread B, and Thread B needs the lock held by Thread A. Classic deadlock!

As it turns out, the CLI specification addresses this issue in section 9.5.3.3 of Partition II, entitled “Races and Deadlocks”:

Type initialization alone shall not create a deadlock unless some code called from a type initializer (directly or indirectly) explicitly invokes blocking operations.

So if we don’t have a deadlock, what happens? Here is the output on my machine:

Begin Foo .cctor on thread Thread A
Begin Bar .cctor on thread Thread B
Bar has a message from Foo: blank
Exit Bar .cctor on thread Thread B
Foo has a message from Bar: Hello From Bar
Exit Foo .cctor on thread Thread A

The message Bar retrieves from Foo is “blank”, but Foo was supposed to initialize the message to “Hello From Foo”. The runtime allowed Thread B to reference Foo before Foo’s static constructor completed! It could have just as easily allowed Thread A to reference Bar before Bar’s static constructor completed, but by letting just one of the threads through, a lock became free and we avoid a deadlock. The runtime cannot perform miracles and let both the constructors run to completion.

The morale of the story is: never touch the static member of another type inside of a static constructor.

C++ programmers knew this was a bad scenario, although for slightly different reasons. See the C++ FAQ for the “static initialization order fiasco”. The punishment for C++ programmers who do this is to take a job at a fast food restaurant, but then hard-core C++ devs are pretty heavy handed (the topic for a future post).

posted by scott with 2 Comments

Database Retirement

I installed SQL Server 2005 Beta 2 last night. This morning I noticed something missing.

If the current bits hold true till RTM, then I will have to lament the disappearance of a dear friend.

Everyone called your design a disaster, but I have fond memories of your eccentricities. Your Order Details table taught me how to delimit identifiers with [ and ]. Your "Ten Most Expensive Products" stored procedure taught me SET ROWCOUNT.

A countless number of articles, books, and newsgroup postings contain the query SELECT * FROM EMPLOYEES – a tribute to your ubiquity. Now they will lie in archived ruins like the statue of Ozymandias.

Farewell Northwind!

posted by scott with 0 Comments

FileVesionInfo

Getting the version number of any managed / unmanaged DLL or executable in .NET 1.0, if I recall correctly, required some magic incantations with PInvoke.

I just discovered the FileVersionInfo class from System.Diagnostics:

FileVersionInfo versionInfo;
versionInfo = FileVersionInfo.GetVersionInfo(@"e:\win2003\system32\svchost.exe");
MessageBox.Show(versionInfo.ToString());

Notice the class overrides the ToString method to provide nicely formatted information:

File:             e:\win2003\system32\svchost.exe
InternalName:     svchost.exe
OriginalFilename: svchost.exe
FileVersion:      5.2.3790.0 (srv03_rtm.030324-2048)
FileDescription:  Generic Host Process for Win32 Services
Product:          Microsoft® Windows® Operating System
ProductVersion:   5.2.3790.0
Debug:            False
Patched:          False
PreRelease:       False
PrivateBuild:     False
SpecialBuild:     False
Language          English (United States)

posted by scott with 1 Comments

Lookout Assembly Hell

I decided to download and try Lookout, the search tool for Outlook (now a free download from Microsoft). I’m hesitant to give out the link, since, like Elvis, it seems to popup and then disappear, but recent sightings have the download at Lookout Software again.

After installation, Outlook greeted me with the following error:

Sorry!! It looks like another Outlook Plugin has installed an unofficial version of the Outlook libraries which breaks Lookout. Lookout will not be able to load. For more information, see this link: http://www.lookoutsoft.com/forums/topic.asp?topic_id=10

Unfortunately, the aforementioned link doesn’t offer many leads on why the problem occurs, nor how to work around it. I have a few COM add-ins loaded, including SpamBayes, some thingy MapPoint installed, and one I wrote myself in C# to redirect email to a web account. I was guessing my software was causing the problem.

I think the problem occurs because Lookout uses the primary interop assembly for Office XP, while the add-in I wrote uses the PIA for Office 2003. I opened my project in the IDE to see if I could get the two working together when all hell broke loose.

Each time I tried to do anything with the add-in project I wrote, Visual Studio crashed and sent an error report. After the error reporting finished, a dialog would appear to tell me updates are available which might fix my problem, and I was sent to the Office updates page. After installing updates, I could not even open Visual Studio without a crash, so I rebooted.

After rebooting, everything appeared to be back to normal, and Lookout started to work once I disabled my C# add-in. I decided this wasn’t a battle I wanted to fight, and scrubbed out every reference to my component from the registry. My add-in isn’t highly useful, but Lookout is fantastic.

posted by scott with 2 Comments

Who Moved My Furniture? (Small Company Life)

On January 31st 2001 the company I worked for closed the doors. A company near Philadelphia had bought all the rights to the software and intellectual property of the former company, and 4 of us were given the opportunity to work for them on a short term consulting basis, starting January 2nd. I had a lead on going to work for a startup company in the video game industry, but it was taking some time to pan out, so I prepared to spend 3 days a week in Philly.

I have to admit I had a bias against Philadelphia going in. When I was a just a young ‘un my parents would drive to Philly to visit an aunt. I have only one memory from these trips, and it goes like this: We are getting ready to go back home. My dad leaves the house to take luggage to the car. Several minutes later he reappears at the door, luggage still in hand, and announces: “somebody stole the car”.

As a kid, the fact that there were people in the world who stole other people’s cars came as a traumatic revelation to me. Based on this experience, and on seeing Eagle’s football games on TV, I hold a terrible stereotype that the city is full of thugs and car thieves. For the longest time I thought the “City Of Brotherly Love” was more of a sarcastic joke instead of a description, but I then I think how close Philadelphia is to the state of New Jersey, so maybe these sayings are all relative.

One morning we arrived at the new company from the hotel at the same time as a tractor trailer. By the time we walked up to the sidewalk the back doors of the trailer were opening. I peered inside, and lo and behold, there was the furniture I used to see every day at work. Suddenly it all came crashing down on top of me. The old company was gone. They new company had really bought everything. I wasn’t just at a client site for a few days. I was a 1099 employee with no office to call home.

Over the next few days we tried to tell people at the new company what great furniture they were getting. We assumed they would love it, because the cubicles they had were old, and small. By contrast, our former company had spared no expense on furniture. Yes, we had cubicles, but they were the nicest cubicles I have ever seen. Spacious, with lots of nooks and crannies for storage, built in lights, and low walls. I hate cubicles as much as the next person, but these were decent.

I have a feeling the employees there were apprehensive about the new cubicles because they didn’t offer as much privacy as they were used to. We knew at least one software developer there who snoozed in the afternoon, but unless you got in really close, which was hard to do, it was impossible to tell.

The lack of privacy at our old office was actually sort of funny, because you knew just a little bit about the lives of other people. It wasn’t eavesdropping you know, it was just hard not to hear conversations like this one from a fellow architect:

“Yes honey, I understand it is your sister’s family, but I’m not just giving them money to go grocery shopping. We’ve tried that before and they waste it. I’ll take them grocery shopping, and I’ll tell you right now, they won’t be buying shrimp and brand name cereal on my dime. If they want cereal they get the generic stuff from Walmart.”

Other people at the other company had a different definition of private matters than I do. One developer sent an email to the staff alias that read like the following (I’m not making this up):

“Does anyone know a good dermatologist in the area? I need to get something lanced.”

When this email hit the inbox, you could just hear it ripple threw the building. People would gasp, or chuckle, or choke on coffee. To this day we still refer to the guy with the nickname of “Lance”.

Seeing familiar furniture in the building only added to the odd feeling I had there. It is tough to adjust to a new corporate climate when you know you are not desperate enough to relocate and stay. For one thing, they took everything too seriously. I tried to spread some cheer by making their Laser Jet printers display random funny messages, but it took them weeks to notice.

During my three weeks in Philly I was amazed to see some of the sales people from our old company appearing at the new company for interviews. I thought this was interesting because the old company went out of business due to a lack of sales, but it didn’t surprise me, because I had learned that sales people have no shame….

posted by scott with 2 Comments

A CEO and His BMW (Small Company Life)

Optimism is a primary trait of startup company CEOs. With all of the risk and obstacles involved in getting a company off the ground, they have to be optimistic. The type of optimism goes beyond “glass half full” optimism. I’ve worked with CEOs who, when spotting an empty glass sitting on the hot asphalt of a desert highway, will convince everyone nearby that a freak microburst of rain is inevitable, and the glass will be full any moment now.

I worked with one of these CEOs during the bubble years. He was a charismatic factory of entrepreneurial ideas. Once the big money came in from the venture capitalists, however, the collective wisdom of higher powers decided the company needed an experienced business person at the helm. We didn’t need optimism anymore, we needed execution. So we acquired a new CEO who was equipped with the people skills of an ostrich and completely devoid of creative ideas.

Actually, I take that back – he did have one idea I can remember. We were working with a customer who built on the Java platform and wanted to use some of our COM+ components. At one point he wandered into a common engineering area and asked if we could “SQL some data around” to provide integration. Other than this, I don’t remember him ever coming out of his office, except for the monthly company meetings.

The company meetings happened every month only because we had monthly layoffs. I suppose these meetings were meant to boost the company morale and assure us everything was under control. It was during one of these meetings when the CEO described layoffs as “a way to scrub the barnacles off the bottom of the boat”. I’ll leave it as an exercise for the reader to determine if these words contain any inspirational value, because it is a subjective call. I can only remember thinking what we really needed during these times was the unabashed optimism of old. Well, that and another $30 million.

During the course of a year we dwindled from a headcount of about 150 people to 12. Sometime near my last paycheck the day came for Mr. CEO to go. The word was getting around that he was packing up in his office. We saw him roll a chair out to his 2-door sports car. We saw him carry a desktop computer to the car. A crowd gathered to watch from afar. Another computer went out the door.

I remember reading once about a contest at a car dealership. The person who could guess the number of golf balls that would fit into an SUV would win the SUV. I’m sure this guy knew exactly how many golf balls fit into his car, because he was using every square centimeter of space. Next to go was a bookshelf. It was incredible to watch.

A mob mentality began to form, and we began to collectively speculate if we should start tearing the place apart and taking it home. Being a mostly civilized group though, I think we ultimately decided just to go out for lunch and celebrate the end of an era. Not that we really had a reason to celebrate, because our time was coming soon too, and by the end of the month the company would officially close the doors. I wasn’t allowed to take any office furniture with me when I left, but it wasn’t the last time I saw my desk….
posted by scott with 4 Comments

The FBI Raid (Small Company Life Flashback)

Years ago I used to juggle two different projects by spending my morning writing C and assembler code for 8-bit embedded CPUs, and in the afternoon I’d switch over to Windows code with Borland’s OWL framework. This was a day I’d never get to launch the Borland IDE.

My office was in a building housing two companies. My company occupied the front of the building, and the second company (let’s call it XYZ Inc.) occupied the back of the building. The only proper way into the back of the building was to go through a door just past my office. These two companies were distinct legal entities, but were closely related. By closely related, I mean the owner of company XYZ called the owner of my company “son”. It was all one big family, if you know what I mean.

As the reader, you need to imagine yourself in my position. You are in a reasonably private area, like an office. You have your favorite music on, and a caffeinated drink by your side. You are cranking out code. There could be a Mardi Gras parade happening outside your window, but you wouldn’t notice, because you are “in the zone”. Such was my situation on this particular morning.

Suddenly, a demanding voice breaks my concentration. “Is this company XYZ?”, the voice says tersely. It was like an order in the form of a question.

Now my first thought, as I was slowly coming out of my concentration, was that if the FedEx delivery guy was going to be this rude, then I had absolutely no obligation to give him a quick answer. In fact, I thought, I might just start by shooting him an annoyed look. I mean, if you value running around lost and interrupting otherwise productive members of the work force with rude questions, give up driving for UPS and join a company who performs ISO 9001 audits.

I turned slowly to the doorway, only to notice a man with a gun on his hip. You can imagine my surprise at having misjudged the situation. Now my lips were already pursed to let out an emphatic “no”, but my brain instantly went off in a number of different directions.

My first thought was how this guy, in his blue windbreaker and jeans, looked like he walked right off the set for the TV show “Cops”. Except “Cops” isn’t filmed on a TV set, it is supposedly “reality television”, and a man with a gun (and a badge on a chain around his neck) was now at the edge of my office staring intently.

My second thought centered on the man’s finger, which was pointing directly into the center of my office, as if this could be the source of all problems in the world. I knew my job now was to divert his attention to some other office in the building, but I was beginning to feel a bit queasy, which led me to my third thought.

My third thought was that I was taking entirely too long in analyzing this situation. I should have long ago calmly replied that the company he was looking for was through the doorway at the end of the hallway, thank you very much, and have a pleasant day. Instead, I was sitting here for what seemed like an eternity, and it suddenly it dawned on me I might appear guilty.

Guilty of what? I thought to myself. What could I have done to attract the attention of a law enforcement officer? But if I wasn’t guilty of something, why didn’t I just answer? Get a grip, I told myself. Quit staring like a deer in headlights and make this unpleasant situation go away.

I never did get to answer, because suddenly a voice in the hallway shouted “it’s through THAT door”, and a parade of 12 armed men moved past and into the second half of the building.

Now, I thought to myself, would be a good time to go to lunch a little early a grab a sandwich.

The deputy at the front door informed me nobody was leaving the building, so I did what everyone else at the company was doing, which was forming a circle in the lobby and speculating as to what was happening in the other half of the building.

Over the next hour or so, agents loaded file cabinets and computers into a rented U-Haul truck, which I thought was interesting. I imagine the FBI does this a few times a year, and maybe if they actually purchased a truck and took decent care of it they could save some taxpayer money over time. On the other hand, you never have to take a rental truck for an oil change, or wait for it to completely stop before switching gears from reverse to drive, so maybe it evens out.

In any case, here was what happened. It seems our sister company imported some electronic components from Japan. These components appeared in medical devices, but the U.S. custom forms said they were intended for cheese analyzers. Oops, an easy mistake to make. Unfortuantely, this lack of attention to detail attracted the attention of several government agencies, including the FDA, U.S. customs, the FBI, and the local sheriff, all who sent representatives on-site that day.

I left that company soon afterwards, but not because of the raid. I had decided I wanted to work for a company whose only product and focus was software. I didn’t know it at the time, but the bubble years were approaching, and small company life was about to get even more interesting...
posted by scott with 4 Comments

Small Company Life

I was thinking back today at some of the weird and funny stuff I’ve lived through at startup companies over the years. Someday I should write in more detail about the following:

The FBI raid.

The CEO who, on his last day, managed to cram 1 executive leather chair, 2 desktop computers, a file cabinet, and a bookshelf into a 2 door BMW.

The intern who wore pink teddy bear clips in his beard.

The CEO who painted his toenails the company colors.

The CFO who was amazed to see how Excel could recalculate cell C3 based on the contents of cell C1.

The CTO who enlisted the aid of a software developer in chasing down escaped chickens back at the farm.

What it is like to show up for work at a new company and see the office furniture from my last company being delivered by tractor trailer.

Why I should not be given the opportunity to take the helm of a yacht for any length of time.

What it is like to have a practicing gastroenterologist at the office part time and how this leads to errant phone calls from people describing the odd color of their stool and demanding advice on what to do about it.

The vice president of global sales who drove a different vehicle to work each day yet never made a sale, and why I think this is because he wore Hawaiian shirts and Nikes during appointments at Fortune 50 companies.

Last but not least: Why engineers should not be required to move office furniture when moving to a new building.

posted by scott with 3 Comments

Server Or Workstation Garbage Collection?

I did some experimentation this evening because I read something that struck me as odd in a comment on Scott H’s blog.

First, some background. There are two versions of the garbage collector for .NET. The garbage collector optimized for multi-processor machines (packaged in MSCorSvr.dll), and the workstation garbage collector (packaged in MsCorWks.dll). I can see who is running the workstation garbage collector on a Win2003 machine using tasklist from the command line:

tasklist /m mscorwks.dll
 
 
Image Name                   PID Modules
========================= ====== ==================
OUTLOOK.EXE                 3352 mscorwks.dll
mmc.exe                     2084 mscorwks.dll
w3wp.exe                    3436 mscorwks.dll

One of the comments suggested going into the .NET Configuration 1.1 MMC in Administrative Tools, right clicking on My Computer, and setting the garbage collection mode to “Run in foreground for server applications”.

This struck me as odd, because in doing some review work for the Performance and Scalability Guide I found out that choosing the garbage collector implementation with a .config file setting was not going to be a runtime feature until the Whidbey timeframe. I tried this configuration option and reset IIS. After hitting a local web application and running taskmgr again my ASP.NET worker process (W3WP.EXE) was still showing mscorwks.dll loaded, not mscorsvr.dll

After a little more digging I discovered the MMC toggles the gcConcurrent element in machine.config:

<runtime> ...
    <gcConcurrent enabled="false" />
</runtime>

It turns out the gcConcurrent setting does not change which garbage collector loads. gcConcurrent only has an impact on the workstation (MsCorWks.dll) implementation of the garbage collector (it is effectively ignored by the server implementation), and furthermore only changes the GC behavior on multiprocessor machines.

With the setting enabled the garbage collector uses an additional thread to build a graph of unreachable objects. The rule of thumb is, gcConcurrent=”true” (default setting) will provide for a more responsive application, but can also let the working set (memory usage) grow larger. You’d have to carefully test an application to see if disabling gcConcurrent actually helps an application’s performance or memory usage. The most detailed source of information I’ve found in one place on this subject is Jeffrey Richter’s book.

<SARCASM>To turn this into a spirited debate, I want to point out that developers who use MsCorSvr.dll on average earn 26% more than developers using MsCorWks.dll. </SARCASM>

Honestly, with all the cycles the .NET community burns on language debates, we could have built another language.

posted by scott with 6 Comments

Generic Gotchas

The introduction of generics will be a welcome addition to C# and VB in 2.0, except the change is little more disruptive than I would have thought. Consider the current use of Hashtable:

Hashtable lastNames = new Hashtable();
lastNames.Add("Beatrice", "Arthur");
lastNames.Add("Lucille",  "Ball");
 
object name = lastNames["Audrey"];
if (name == null)
{
    lastNames.Add("Audrey", "Hepburn");
}

Now here is how it might look after an porting to use the generic type Dictionary<K,V>:

Dictionary<string, string> lastNames;
lastNames = new Dictionary<string, string> ();
lastNames.Add("Beatrice", "Arthur");
lastNames.Add("Lucille", "Ball");
 
// the next line throws KeyNotFoundException
string name = lastNames["Audrey"];
if (name == null)
{
    lastNames.Add("Audrey", "Hepburn");
}

In Beta 1 the indexer throws an exception if the given key does not exist in the collection. If this is not desirable behavior, you can use the ContainsKey method to check safely if a given key exists. The current behavior makes porting code based on Hashtable to Dictionary<K,V> a bit trickier.

I think the current behavior is justified. What would happen with a Dictionary of integer values when you pass a key that does not exist? There is no possibility of returning null for a value type, and returning a default value (0) seems misleading and bug-prone.

Another gotcha is in the second sentence of the documentation for every generic type:

This class is not CLS-compliant

The question is: Do I care?

I’ve read articles about how being CLS compliant will allow for interoperability with a wider range of .NET languages. This could be important for library designers targeting the 0.4% of the market using Cobol.NET and Fortran.NET. I did a quick test to see the impact on the other 99.1%. First, I put the following in a C# class library:

public class Class1
{
    public Dictionary<string, int> GetDictionary()
    {
        Dictionary<string, int> foo = new Dictionary<string, int>();
        foo.Add("test", 2112);
        return foo;
    }
}

Next, a quick VB program to use the C# class. (I was a little worried I might have to dig to find generics syntax for VB, but my fingers had a spasm and intellisense auto-completed the entire program. It was amazing. Did I mention my cat wrote a Tetris knock-off with Whidbey last week?).

Sub Main()
    Dim c As New ClassLibrary1.Class1
    Dim bar As Dictionary(Of String, Int32)
    bar = c.GetDictionary()
    Console.WriteLine(bar("test").ToString())
End Sub

It all just works.

For the applications I work on, generics are powerful enough to sacrifice CLS compliance. I imagine this will be the case for the majority of developers. Porting an existing codebase heavily into collections to the generic types won’t be automatic, but nothing to sweat over if all the unit tests are written, right?

posted by scott with 5 Comments

Book Shopping

I've been running low on reading material, so I decided it was a good time to go book shopping.

One title that has caught my eye with it's quirkiness is Coding Slave. Judging by the web site, this should be entertaining.

I also found out Neal Peart has a new book on the way. I'm just wondering if I should pre-order through Amazon, or wait until the Rush tour hits Virginia this August. Pehaps some copies might be available for sale there. Decisions, decisions.

posted by scott with 0 Comments

More Fun With Generics: Action, Converter, Comparison

As a follow up to yesterday’s blog about the Predicate<T> delegate, I wanted to try out the three additional delegate types in the generics area.

First, a new type to work with:

class Person
{
   public Person(string name, DateTime birthday)
   {
       this.name = name;
       this.birthday = birthday;
   }
 
   public string Name
   {
       get { return this.name; }
       set { this.name = value; }
   }
 
   public DateTime Birthday
   {
       get { return this.birthday; }
       set { this.birthday = value; }
   }
 
   string name;
   DateTime birthday;
}

The Comparison<T> delegate represents a method used to compare two types. If you have ever needed to define an entirely new type deriving from IComparer just to tell Array.Sort how to compare two objects, you’ll appreciate the brevity in the following sample.

List<Person> list = new List<Person>();
 
list.Add(new Person("Alex", DateTime.Now.AddYears(-30)));
list.Add(new Person("Neal", DateTime.Now.AddYears(-20)));
list.Add(new Person("Geddy", DateTime.Now.AddYears(-25)));
 
list.Sort(
      delegate(Person x, Person y)
      {
        return Comparer<DateTime>.Default.Compare(x.Birthday, y.Birthday);
      }
 );

Next is the Converter<T,U> delegate. Use this delegate to convert each object of type T in a collection to type U.

List<int> yearList;
yearList = list.ConvertAll<int>(
        delegate(Person p)
        {  
            return p.Birthday.Year;
        }
   );

Finally, there is the Action<T> delegate. Use this delegate to perform an action with each object of the collection.

yearList.ForEach(
        delegate(int year) { Console.WriteLine(year); }
    );

I am generally grouchy about any new language feature until I can write some code and figure out its purpose in life. Generics I knew would be a hit, and after writing this code I’m starting to warm up to anonymous delegates.

posted by scott with 5 Comments

Generics and Predicates

What will be an elegant technique to remove objects matching a condition from a List in C# 2.0?

If the following code finds a match, we’ll find out it’s a no-no.

foreach (string s in list)
{
    if (s == "two")
        list.Remove(s);
}

In VS2005, the code creates this friendly little dialog.

C# 2.0 introduces generics, and with generics come predicates. A predicate returns true when an object meets a set of conditions, otherwise false. A method like List.RemoveAll will run each object in the collection through a given predicate to test each object for a match. When the predicate returns true, the method removes the object from the collection. The nifty thing is, you can write the predicate as an anonymous delegate:

list.RemoveAll(
    delegate(string s)  { return s == "Two"; }
);
 

Alternatively, you can keep your logic inside a named method.

static bool MatchTwoPredicate(string s)
{
    if (s == "Two")
        return true;
    return false;
}

// and later . . . 
 
list.RemoveAll(MatchTwoPredicate);

I feel either technique is easier on the eyes when compared to STL and functors in C++. Then again, I should be sleeping right now instead of blogging.

posted by scott with 3 Comments

Does Michael Powell Have The Ugliest Blog On the Planet?

While veering through Yahoo news this evening I came across the headline: “FCC Boss Launches Blog Aimed at High-Tech Industry”.

I was stunned.

For the first time ever I read about a new blog from a source outside the blog world. Usually you find out about these sorts of thing by plowing through 25 insightful blog entries which read: “so and so is blogging – subscribed!”.

In true Yahoo / Reuters fashion, however, the news article didn’t contain an actual link to the blog, but links to news and websites about the FCC. At the very bottom of the article, they put in the URL, but not in a hyperlink. I cut and pasted the URL into IE.

I was stunned.

I really thought I had reached the wrong server. I see a big broken banner on the top because ActiveX controls are disabled for the Internet zone. Advertisements and menus appear randomly on the page, and there is a huge gap of whitespace to scroll through before blog entries appear.

[update: i've been informed this is because I also have JavaScript disabled in the Internet zone. DUH! Ah, the pleasures of running Win 2003 Server and hardened security on a desktop machine. Still - the colors give me a headache.]

Then I reached the bottom of the page, which included more advertisements from Sun, IBM, and AOL. On a hunch, I viewed the page in Firefox. Suddenly, the layout improved. Menus aligned. Caverns of white space turned into proper half inch borders.

The colors still give me a headache, but it’s hard to cram 22 advertisements on a page without looking like a dryer full of checkered golf clothes.

Interesting that the head cheese of the FCC has a blog that doesn’t render well in the most popular browser on the planet. [update: ok, maybe it does render with everything enabled, but it's still UGLY!]

posted by scott with 0 Comments

ASP.NET 2.0 and Site Maps

I hereby interrupt the “week of the malcontent” with the “evening of possible enlightenment”.

The provider design pattern in ASP.NET 2.0 is sweet. I’ve been toying around in the SiteMapProvider area since the first CTP. There is an XmlSiteMapProvider which let’s you describe the navigation and layout of your web site in an XML file like so:

<?xml version="1.0" encoding="utf-8" ?>
<siteMap>
  <siteMapNode title="Home" url="Default.aspx" >
    <siteMapNode title="Products" url="Products.aspx">
      <siteMapNode title="Seafood" url="Seafood.aspx"/>
      <siteMapNode title="Produce" url="Produce.aspx"/>
    </siteMapNode>
    <siteMapNode title="Contact" url="Contact.aspx">
      <siteMapNode title="Email Us" url="Email.aspx"/>
      <siteMapNode title="Phone List" url="Phones.aspx" />
    </siteMapNode>
  </siteMapNode>
</siteMap>

Without writing a line of code (just some drag and drop operations), you can give all the pages in your site a tree view of the site hierarchy and a bread crumb control:

What if your site navigation comes from a database table?

NodeID URL           Name     ParentNodeID 
------ ------------- -------- ------------ 
1      Default.aspx  Home     0
2      Products.aspx Products 1
3      Seafood.aspx  Seafood  2
4      Produce.aspx  Produce  2
5      Contact.aspx  Contact  1
6      Email.aspx    Email    5
7      Phones.aspx   Phone    5

All you need to do is derive from the abstract class SiteMapProvider and override a handful of methods, like GetParentNode and GetChildNodes. These methods can be straightforward to implement with a few pre-built collections of type Dictionary<string, SiteMapNode>. SiteMapNode objects represent the nodes in the site map, while a Dictionary is one of the exciting new classes from the System.Collections.Generic namespace, which you can use to build strongly typed collections.

One you have some code querying SQL Server and implementing the SiteMapProvider methods, you just need to tell the runtime about your new provider via a config file:

<siteMap defaultProvider="MySqlSiteMapProvider" enabled="true"> 
  <providers> 
    <add name="MySqlSiteMapProvider" type="SqlSiteMapProvider"
         connectionStringKey="ConnectionString"/> 
  </providers> 
</siteMap> 

You can have multiple providers for a site. If half of the site navigation information comes from XML and the other half from the database, that’s quite possible. It will be interesting to see what other providers come out. I'm sure SQL, and File System providers will be in demand.

posted by scott with 22 Comments

Why Do Microsoft Webcasts Have To Stream?

The MSDN Webcasts Weblog is online. Since I am doing nothing but whiney posts this week, then I’d like to ask: Why can’t we download the webcasts for offline viewing?

Bill has me salivating over the Personal Media Center. I started to imagine myself downloading MSDN TV, Channel 9 videos, and TechEd webcasts to watch at my leisure, away from the desktop. There are just two problems with this dream:  

  1. The Personal Media Center isn’t for sale as yet.
  2. The Microsoft webcasts do not download as a file I can save, they only stream.

[Updated with MSDN Webcasts new URL].

posted by scott with 7 Comments

Yearning for Yukon

Let me say that the Express version of SQL 2005 has not been a disappointment to me.

The disappointment has been in not getting a new beta of the ‘real thing’, the ‘Venti espresso’, the ‘yellow yolk of the Yukon egg’.

I have not tried to do much with SQL Express. As soon as I heard the product mentioned in the same sentence as MSDE, I pictured it appearing in the Server Explorer window of the IDE, doing all the mundane things databases have done for the last 5 years. I think a previous forced experience in wrestling with MSDE helped me figure out some of the quirks, like hunting down the instance name to make a connection [use (local)\SQLEXPRESS].

I did come across an interesting error message. I was curious to see if SQL Express, like MSDE, defaults to Windows Authentication only (and it does). In toying around, I tried to “sp_addlogin ‘user’, ‘user’” (just as a test, you see, to set the password the same as the username), and had the following thrown back at me:

 
Password validation failed. The password does not meet policy
requirements because it is not complex enough. 

Interesting.

Also interesting: I came across a SQL Express rant and a MySql success story in back to back posts this evening. I hope something gets released before the trend continues.

UPDATE: One more SQL Express rant, and a SQL Express success.

posted by scott with 0 Comments

Office Needs A Better Managed API

A few days ago, I decided I wanted a new button on my Outlook toolbar. When I click the button I want highlighted items redirected to a web mail account with the ‘From’ address intact. I’m sure this already exists somewhere, but I wanted to learn how to do it myself.

With the Shared Add-In extensibility project wizard and code from “An Introduction to Programming Outlook 2003 Using C#”, I thought I was 90% of the way there, except it didn’t work. Specifically, the following line of code from the article would never return:

CommandBars commandBars = applicationObject.ActiveExplorer().CommandBars;

The call would literally disappear in the opaque goo of COM interop. No exceptions, no error dialogs, no abnormal behavior as Outlook continued to work. I thought I must have a configuration problem and began double-checking primary interop assembly versions and looking for updates. I happened to run across a knowledge base article using the following code:

activeExplorer = applicationObject.GetType().InvokeMember("ActiveExplorer",BindingFlags.GetProperty,null,applicationObject,null);
commandBars= (CommandBars)activeExplorer.GetType().InvokeMember("CommandBars",BindingFlags.GetProperty,null,activeExplorer,null);

The above code, using reflection, worked perfectly. I managed to finish the code for my button click event, but not without some irritation.

The base class library in .NET spoils developers, and I think if Microsoft wants people to develop for Office they should provide a higher level of abstraction on top of the runtime callable wrappers. The interface should be subject to the same design rules and usability testing as the rest of the .NET libraries. Let me give you a couple examples about why I am griping.

Selected items are kept in a Selection collection. Indexing into the collection gives me a plain object reference. It would be nice if there was a base class representing any type of item in Outlook which I could perform some operations on. As it stands, I had to dig through the documentation to find the types of Items I am interested in: MailItem and PostItem objects. I had to find these items in the object browser of the IDE as the documentation I used (VBAOF11.chm – the Microsoft Office Object Model) make no mention of them.

Without documentation I decided the best way to get to know these classes was by inspecting them in the debugger. Unfortunately, if I cast an object reference to type MailItem, all I see in the debugger quick watch is a System.__ComObject, which gives me nothing to go on. If, however, I cast the reference to the interface type of _MailItem (notice the underscore), then I can see all the properties and values I am interested in.

The fact that there are three types available to work with (MailItem, _MailItem, and MailItemClass) only adds to the confusion. My fading COM memories tell me these types probably exist because of the difference is dispatch and vtable binding, but when I just want to get something done in Outlook I don’t really care to learn the differences. I just wish it was easier, and with integrated documentation, like the rest of the .NET development experience. Whine, whine, whine.

P.S. I found the easiest way to debug an add-in which is loaded by Outlook when Outlook starts is to invoke System.Diagnostics.Debugger.Launch(), and let's not talk about the number of times you need to put in System.Reflection.Missing.Value as a parameter to a method. Complain, complain, complain.

posted by scott with 6 Comments