Tablet UML News


News and commentary (and whatever else catches my eye)
from Martin L. Shoemaker, author of Tablet UML
and UML and Tablet PC instructor for The Richard Hale Shaw Group

Monday, January 30, 2006

What a long, strange trip
iPaq Power Connector

The item pictured above is an iPaq Power Connector. The power adapter plugs into the synch cradle, and then I plug the iPaq into the synch cradle to recharge the batteries. With the iPaq Power Connector, I can plug the power directly into the iPaq, skipping the cradle. The iPaq Power Connector has a little rubber loop that fixes it to the power adapter cable; but it's flexible, and detachable.

Earlier this month, as I wrapped up the power connector, I felt some resistance. I tugged on it, and it came free from whatever it was caught on; but when it did, the iPaq Power Connector was gone. I looked under the bed, under the backpack, under the power strip, and under every other thing I could see that might have both caught and concealed the iPaq Power Connector. No luck. It was gone.

So ever since, everywhere I've taken my iPaq, I've had to also take the synch cradle if I've wanted to be able to recharge my phone. I stuck it in my backpack, and I took it everywhere: to Kinko's multiple times, to McDonald's and various other restaurants, to friends' houses, you name it. Even on a flight from Grand Rapids to Yonkers and back by way of Detroit. Everywhere I went, I had the synch cradle in my backpack, which wasn't exactly convenient: it's an odd shape and size, and makes it harder to fit the backpack into tight places like under airline seats. But especially on business trips of multiple days, I have to be able to recharge the phone.

This latest trip to San Francisco started with a stop in Minneapolis. And Saturday travel is pretty light, so NWA uses smaller planes where they can. This time, the plane was a small one with very limited overhead luggage space. The gate agent strongly insisted on doing gate checks for all luggage. Actually, the backpack could've fit under the seat just fine — even with that bulky synch cradle in it — but I didn't know that. So against all my usual habits, I let the gate agent tag the backpack; and then when I got to the plane, I put it on the cart for checking. I figured it was only an hour flight, and I could be without my CX200X for that long. Besides, I had some new reading to keep me occupied.

So when I got to Minneapolis, I rushed to the gate check pickup shelf. Just because I gave the machine up didn't mean I was comfortable with it sitting on a shelf where anyone could pick it up. But thanks to some slow passengers, "rushed" wasn't quite the right word. By the time I got to the shelf, my backpack was the last piece of luggage there.

And on the floor, right below where my backpack lay, was... my iPaq Power Connector.

I can't even fathom the odds...
You keep using that word. I do not think it means what you think it means. (II)
And the word in question this morning is "retirement". And it's hard to believe of a man who has written so many books, but apparently Stephen King just doesn't know the meaning of the word. And here's more proof. And more (though he might be forgiven for that one, since it's a non-fiction book about a once-in-a-lifetime event that he as a fan must have savored). I can think of a lot of authors who would love to be so "retired".

The man really just can't help himself. He will write, and no resolution is going to stop him.

Unfortunately, his latest work (Cell) demonstrates why he went into "retirement" in the first place. It's not a bad book at all. Mr. King has a natural talent that makes bad writing all but impossible for him, so the book reads well.

But one thing that led to his "retirement" was his feeling that he was repeating himself, that he had somehow mined all his ideas. This feeling came to him when he wrote From a Buick 8, which bore a superficial but unmistakable similarity to Christine. While the books are very different in almost every way, both are at the core stories about myserious cars which control and possess the lives of the people that encounter them. As Mr. King said in an interview on the Mitch Albom show (paraphrased), "Wait a minute. Haven't I been here before?"

And that's the problem with Cell: it has superficial but strong echoes of The Stand. That book told the story of a sudden release of an engineered virus that wipes out most of the world's population. A few of the survivors then go on a road trip toward some looming confrontation between Good and Evil.

And Cell? It tells the story of a mysterious signal that goes out over cell phones, transforming most of the civilized world's population into drooling zombies that slowly evolve into a group mind. A few of the survivors then go on a road trip toward some looming confrontation with the group mind.

Does that make Cell a rehash of The Stand? No. For one thing, it's only one-third the length. For another thing, it's much smaller in scope, both thematically and geographically.

But if Mr. King wanted to avoid repeating himself, this book was not the way to do it. That's not a criticism of the book itself — I'm quite enjoying it, actually — but I think it points out a flaw in his reasoning when he "retired" in the first place. When you write as many books as he has, you can't help revisiting old themes and motifs. He has largely covered the field already, so there's little room for truly new works. And honestly, I think all great artists revisit and build on their earlier works. For that matter, other artists build upon their ideas. So why shouldn't they?

Related Posts (on one page):

  1. You keep using that word. I do not think it means what you think it means. (II)
  2. You keep using that word. I do not think it means what you think it means.

Tuesday, January 17, 2006

Gateway Disillusionment, Part II
I still really love my Gateway CX200X; but over time, I'm finding minor little design choices that I just would've done differently if I were designing it.

Today's design flaw isn't news, but it has gotten more and more annoying as I've been watching Star Trek (thank you, Sandy!) on the external monitor. Oh, the Gateway performs quite nicely: at one point I had the DVD running in an external drive, a DVD in the internal drive installing software onto a Virtual PC image, another Virtual PC image downloading service packs from Microsoft (via T-Mobile GPRS cellular modem), and email downloading to the "real" PC via sharing the same GPRS connection; and while the DVD skipped a little here and there, it was watchable. That's an awful lot for one machine to keep up with.

No, my complaint is simply this: whoever designed the external monitor plug for this machine never bothered to include screw holes. So every so often, sometimes right in the most exciting part — the video plug falls out. Aaaarrrrgggghhhh!!!!

Now ignore, for the moment, that my machine is in my lap while I'm working, and thus easily jostled. (Red card! No, I don't expect any non-fencers understood that.) But this thing is a Tablet PC. That means it's mobile. Now that may very well have been the reason for no screw holes: it allows a "quick release", so that moving the Tablet PC can't pull over the monitor. But when I give Tablet PC demos, I often pick the machine up, tilt it to show people how it works and how you rotate the screen, etc.; and sure as shootin', that video cord is going to fall out, every single time.

Oh, well. I still think it's a great machine: great development platform, great teaching platform, and great DVD-watching platform.
Richard Hale Shaw says, "Put up or shut up!"
Well, maybe that's not exactly how he put it; but he referenced this post, where I wrote:


Richard Hale Shaw makes an interesting argument against the C# using statement (not the using directive; and thank you, C# team, for that bit of confusing language). I disagree with him; but it will take time and sleep before I can fully explain why. The short preview: he says you can't force people to use your class correctly; I say I can, and I'll show you how, soon.


And he writes:


Always wondered what you had in mind.


Well, he's right: it's way past time I finished this thought!

Fair warning: the rest of this post is code, code, code! Instead of reading further, you non-programmers may instead prefer to go look at the cute squirrel.

****************************************************************

OK, now that only geeks and masochists are left, let's review the highlights of Richard's argument for why the C# using statement isn't very helpful. Here are some excerpts and comments:


And more and more developers are discovering the third variation or using statement: using using for early disposal:

using(MyObj obj = new MyObj())
{

obj.DoStuff();

}


When the C# compiler encounters this use of using, it will only compile correctly if the target — in this case, obj — implements IDisposable (and therefore, IDisposable.Dispose).


Actually, I recently discovered this isn't quite true. The class of the object need not implement IDisposable, as long as one of its ancestor classes does. As long as the object may be cast to an IDisposable, it doesn't matter whether that's through the ultimate class or some ancestor class. Thus, for instance, a StreamWriter object can be used in a using statement, even though StreamWriter doesn't implement IDisposable. Why? Because StreamWriter inherits from TextWriter, and TextWriter does implement IDisposable. For a while, I would diligently look up each class before using it in a using statement, checking to see if it implements IDisposable. Now I've decided that, when in doubt, I'll just stick it in a using statement, and let the compiler tell me if there's no IDisposable to be found. If it does any work with files or ports or graphics resources, I just assume IDisposable until proven otherwise.




Continuing with excerpts from Richard's post:


In the resulting IL, the compiler takes what you put inside the block (or if you didn't use a block, the single statement that would follow the using statement) with a try...finally block:

IL_0000: newobj instance void ObjectDisposal.MyObj::.ctor()
IL_0005: stloc.0
.try
{

IL_0006: ldloc.0
IL_0007: callvirt instance void ObjectDisposal.MyObj::DoStuff()
IL_000c: leave.s IL_0018

} // end .try
finally
{

IL_000e: ldloc.0
IL_000f: brfalse.s IL_0017
IL_0011: ldloc.0
IL_0012: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0017: endfinally

} // end handler



Now here's a difference between Richard and me: he loves IL code, while I'd rather not look at it unless I have to. What he's saying, in plain C#, is that the using block above is equivalent to this:


MyObj obj = new MyObj();
try
{

obj.DoStuff();

} // end .try
finally
{

obj.Dispose();
endfinally

} // end handler


There, isn't that a lot more comprehensible all all that nasty IL code?

Unfortunately, even though you'll often see people "translate" that using block that way, it's also wrong. Foreshadowing one of Richard's later points, it's important to note that in this using block...

using(MyObj obj = new MyObj())
{

obj.DoStuff();

}


...the object obj is out of scope at the end of the block, and may no longer be referenced. Because it was declared within the using statement, its scope ends when the using statement ends — which means, in fact, the closing curly brace. So a truly proper C# "translation" of that using block would look like this:


{

MyObj obj = new MyObj();
try
{

obj.DoStuff();

} // end .try
finally
{

obj.Dispose();
endfinally

}

} // end handler


Note the extra curly braces needed to define a scope block that encompasses obj.

Continuing again with excerpts from Richard's post:


But there's nothing automatic about using statements: the client or user of the class has to add them. That's no more automatic than manually calling Dispose yourself.


And here's where I'm going to differ with Richard: while we can't make using automatic, we can add code that makes it extremely visible when someone has failed to dispose of resources properly. We can't force client code to be written well, but we can nudge really strongly. I'll explain the details at the end of this post.

There's also a way in which using is, if not automatic, then easier. For one thing, it's just plain less typing and less formatting than a try/finally. I tell my students that I'm the laziest programmer on the planet, and I want to make my job as easy as possible. And I encourage them to adopt the same attitude: they should think, and the tool should work, not the other way around. Plus using is almost always a good habit if not misused (as Richard discusses below); and I like to program good habits into my fingers, so that good code just sorta naturally flows out. Almost automatic, you might say.

I would also contend (since I can't help being pedantic) that there's something slightly automatic about using: it provides that implicit scope block described above, which lets the compiler tell you when someone tries to access the disposed object out of scope. Of course, that will lead into a problem that Richard very properly describes farther down:


And if the syntax above was the only way you could use using (where the target is instantiated in the parameter list), I'd have no objection to it whatsover. But the fact is that the target can be instantiated anytime prior to the using statement as well:

MyObj obj = new MyObj();
...
using(obj)
{

obj.DoStuff();

}


My problem with this is that you could still have what appear to be valid calls to methods/properties on what is now a disposed object:

MyObj obj = new MyObj();
...
using(obj)
{

obj.DoStuff();

}
...
obj.DoStuff();


Oh, and the compiler is NOT going to help you here.


Yep. Absolutely. This is a real problem, and you have to tread cautiously. I have run into a case now and then where I wanted to use Dispose on a previously allocated object. It's uncommon, but not necessarily wrong.

We should always prefer compiler-automatic to catch problems whenever possible. Relying on people to get it right can get us into trouble, because people are, well, people. They make mistakes. As Richard wrote:


The Dispose Pattern says that once Dispose has been called, subsequent calls to Dispose should be benign (do nothing) but subsequent calls to any other public operation should throw an ObjectDisposedException. So now we have a case where a developer thinks they've automated (or semi-automated) resource disposal, but could use the object again as well.

It's just too confusing: there's no way to know that the object has been disposed unless you know what the using statement does internally. If you know that, of course, you'd make it a Best Practice to avoid using using, or avoid using using without instantiating the target in the parameter list. I know this. You know this if you've attended one of my classes, or someone else's class, or read it in a book or figured it out yourself.

But how do you count on someone else — who's now charged with modifying and maintaining this code base — knowing it? You can't and you don't.


To me, Richard hasn't diagnosed a problem with using; he has diagnosed a problem with IDisposable, and with .NET, and in fact with resource management in general in a memory-managed environment: even though the environment is cleaning up discarded memory for you, you can't guarantee people will free up their non-memory resources when they're done with them.

In other words, he has detected the Return of the Sandwich.




So if the Sandwich only works if everyone knows — and remembers — to use it, that to me is not a using problem: using is just a particular form of the Dispose Pattern, which is a specialized form of the Sandwich Pattern, which relies on fallible humans. The problem is rather that sometimes people don't clean up, whether they're using using or try/finally or whatever. And there's just no way for the compiler to detect that. Now the runtime environment can catch it, because things will fail; but when it does, the results are usually really ugly. We're not back in the days of the 64K limit, and it's pretty hard for an app to crash another app these days; but a poorly performing app can certainly drag down the whole system.

But even worse is that often things won't fail. On your testing platform, the sloppy code never happens to hit a limit, so you never notice the problem until you ship. And then, of course, your customers find it. Or maybe your testers can tell that something's wrong, because the system starts misbehaving; but they can't diagnose what went wrong. In some ways, it's back to the bad old Win3.0 days: the problem doesn't pop up with the resources that haven't been freed; it pops up in other places, where requests for new resources fail, and then code crashes when it can't get those resources. (Yes, good code should be written to test for a failure to get a resource, and to fail gracefully in response. Wanna bet on how many programs actually do that?)

****************************************************************

So it seemed to me that what we really needed was a way to detect and report undisposed objects. And with a little thought, I realized I could do just that. The result is the class I call MustDispose. Here's the code, all in one chunk. After it's done, I'll dissect it for the important parts.






////////////////////////////////////////////////////////////////////////
// Class MustDispose
// Copyright (c) 2006 by Martin L. Shoemaker, The Tablet UML Company
// Permission is granted to reuse this code within any project, in whole
// or in part or in altered form, as long as this copyright statement
// is included along with any portion or modification of this code or
// of any work derived from this code.
////////////////////////////////////////////////////////////////////////

// Using the following namespace.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;

// MustDispose is part of the NutsAndBolts library.
namespace TabletUMLCompany.NutsAndBolts
{

/// <summary>
/// Class MustDispose. Use this within an IDisposable implementation
/// to ensure that either the object is disposed, or a record is made.
/// </summary>
/// <example>
/// public class DisposableClass : IDisposable
/// {
/// // The single MustDispose.
/// private MustDispose mDispose = new MustDispose( true , true , "This object holds a brush, which must be released back to Windows when no longer needed." );
///
/// // The brush that we must release when we're done.
/// protected Brush mBrush = null;
///
/// // The color.
/// private Color mColor = Color.White;
///
/// // The color. We will always create a matching brush.
/// public Color Color
/// {
/// get
/// {
/// // Note how we use the Test method of the MustDispose
/// // to verify that we're not disposed yet. It will
/// // throw the appropriate exception if we ARE disposed.
/// mDispose.Test();
/// return mColor;
/// }
/// set
/// {
/// // Note how we use the Test method of the MustDispose
/// // to verify that we're not disposed yet. It will
/// // throw the appropriate exception if we ARE disposed.
/// mDispose.Test();
/// mColor = value;
/// DisposeBrush();
/// mBrush = new SolidBrush(mColor);
/// }
/// }
///
/// // Clean up the brush.
/// private void DisposeBrush()
/// {
/// // Note that we DON'T need a call to mDispose.Test() here.
/// // Since this is a private method, we're going to assume that
/// // we'll only call it when appropriate.
///
/// if (mBrush != null)
/// {
/// mBrush.Dispose();
/// mBrush = null;
/// }
/// }
///
/// // The Finalizer. Clean up here, if nowhere else.
/// ~DisposableClass()
/// {
/// // Call the internal Dispose, as per Wagner.
/// Dispose(false);
/// }
///
/// // The internal Dispose, as per Wagner.
/// protected virtual void Dispose(bool disposing)
/// {
/// // Ask the MustDispose whether it has been disposed yet.
/// if (!mDispose.Disposed)
/// {
/// if (disposing)
/// {
/// DisposeBrush();
/// }
/// }
///
/// // Dispose the MustDispose. VERY IMPORTANT! Otherwise, the
/// // MustDispose will falsely report resource leaks.
/// mDispose.Dispose();
/// }
///
/// // The standard Dispose implementation, as per Wagner.
/// public void Dispose()
/// {
/// Dispose(true);
/// GC.SuppressFinalize(this);
/// }
/// }
/// </example>
public class MustDispose : IDisposable
{

#region Fields.

/// <summary>
/// The type name of the object which was allocated but not disposed.
/// Defaults to this type name.
/// </summary>
private string mOwnerTypeName = "MustDispose";

#endregion

#region Properties with fields.

/// <summary>
/// Have we disposed this MustDispose yet?
/// </summary>
private bool mDisposed = false;

/// <summary>
/// Have we disposed this MustDispose yet? Read only.
/// </summary>
public bool Disposed
{

get { return mDisposed; }

}

/// <summary>
/// Are we supposed to throw an exception when an object is lost?
/// </summary>
private bool mThrow = true;

/// <summary>
/// Are we supposed to throw an exception when an object is lost?
/// </summary>
public bool Throw
{

get { return mThrow; }
set { mThrow = value; }

}

/// <summary>
/// Are we supposed to log an event when an object is lost?
/// </summary>
private bool mLog = false;

/// <summary>
/// Are we supposed to log an event when an object is lost?
/// </summary>
public bool Log
{

get { return mLog; }
set { mLog = value; }

}

/// <summary>
/// An optional reason why Dispose is required.
/// </summary>
private string mReason = "";

/// <summary>
/// An optional reason why Dispose is required.
/// </summary>
public string Reason
{

get { return mReason; }
set { mReason = value; }

}

#endregion

#region Construction and initialization.

/// <summary>
/// Simple constructor. Sets the type name.
/// </summary>
public MustDispose()
{

mOwnerTypeName = GetUndisposedTypeName();

}

/// <summary>
/// Another constructor. Sets the control flags.
/// </summary>
/// <param name="throwIfLost">True if we should throw an exception for a lost object.</param>
/// <param name="logIfLost">True if we should log an event for a lost object.</param>
public MustDispose(bool throwIfLost, bool logIfLost)

: this()

{

mThrow = throwIfLost;
mLog = logIfLost;

}

/// <summary>
/// Most detailed constructor. Sets the control flags, and also a reason why
/// disposing would be a good idea.
/// </summary>
/// <param name="throwIfLost">True if we should throw an exception for a lost object.</param>
/// <param name="logIfLost">True if we should log an event for a lost object.</param>
/// <param name="reason">What will go wrong if we don't dispose of the owner obect?</param>
public MustDispose(bool throwIfLost, bool logIfLost, string reason)

: this(throwIfLost, logIfLost)

{

mReason = reason;

}

#endregion

#region Destruction and clean-up.

/// <summary>
/// Finalizer.
/// </summary>
~MustDispose()
{

// Call the inner Dispose, as per Wagner.
Dispose(false);

}

/// <summary>
/// The internal Dispose, as described in Wagner's Effective C#.
/// The purpose of the internal Dispose is to have a Dispose with chaining up an
/// inheritance hierarchy, via virtual and override. This class is a root class,
/// so does not need to chain up. At this time, there are no derived classes;
/// but we're allowing for the possibility.
/// </summary>
/// <param name="disposing">
/// True if this was called as part of an IDisposable.Dispose call; false if this
/// was called as part of a finalizer.
/// </param>
protected virtual void Dispose(bool disposing)
{

// Multiple Dispose calls must be nondestructive.
if ( !mDisposed)
{

// We're disposed now. We need to set this flag RIGHT NOW. Otherwise, if we get
// some sort of exception below, we'll fail the Dispose Pattern rule that
// multiple Dispose calls must be non-destructive. That's actually not very
// likely to be a problem (because any exceptions are only likely to occur
// during finalization and Dispose calls after that are highly unlikely); but
// better safe than sorry.
mDisposed = true;

// If we're called as part of a finalizer and we haven't been disposed
// yet, that's a problem. The owner object expected to be disposed, dang it!
if (!disposing)
{

// First, assert that we're disposing. Then possibly take harsher measures.
System.Diagnostics.Debug.Assert(disposing, GetNotDisposedMessage());
// Throw an exception, if expected.
if (Throw)
{

ThrowNotDisposed();

}

// Log an event, if expected.
if (Log)
{

LogNotDisposed();

}

}

}

}

#endregion

#region IDisposable Members

/// <summary>
/// The external dispose.
/// </summary>
public void Dispose()
{

// Call the internal Dispose, as per Wagner.
Dispose(true);

// Suppress finalization. Not needed for final clean-up now.
GC.SuppressFinalize(this);

}

#endregion

#region Public worker methods.

/// <summary>
/// Test to ensure this has not been disposed yet. Throw the
/// appropriate exception if it has.
/// </summary>
public void Test()
{

if (mDisposed)
{

ThrowDisposed();

}

}

#endregion

#region Private worker methods.

/// <summary>
/// Get the message to use when warning about a failure to dispose.
/// </summary>
/// <returns>The message.</returns>
private string GetNotDisposedMessage()
{

string result = "Object of type " + mOwnerTypeName + " was not disposed. Possible resource leak!";
if (Reason != "")
{

result += Environment.NewLine + Reason;

}
return result;

}

/// <summary>
/// Get the message to use when warning about using a disposed object.
/// </summary>
/// <returns>The message.</returns>
private string GetDisposedMessage()
{

return "Object of type " + mOwnerTypeName + " was used after being disposed. Possible corrupt resources!";

}

/// <summary>
/// Get the type name of the object which was not disposed.
/// </summary>
/// <returns>The type name.</returns>
private string GetUndisposedTypeName()
{

try
{

// We're going to use System.Diagnostics and System.Reflection
// to find the owner object. Start by getting a stack trace.
StackTrace st = new StackTrace();

// Walk the stack, looking for a type other than MustDispose.
// That will be the owner type.
Type tThis = this.GetType();
for (int i = 0; i < st.FrameCount; i++)
{

// Get the stack frame and the method.
StackFrame sf = st.GetFrame(i);
MethodBase m = sf.GetMethod();

// Compare to MustDispose.
if (m.DeclaringType != tThis)
{

return m.DeclaringType.Name;

}

}

}
catch
{
}

// Never found an owner.
return this.GetType().Name;

}

/// <summary>
/// Throw a not-disposed exception, with explanation.
/// </summary>
private void ThrowNotDisposed()
{

throw new Exception(GetNotDisposedMessage());

}

/// <summary>
/// Log a not-disposed exception, with explanation.
/// </summary>
private void LogNotDisposed()
{

string appName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
EventLog.WriteEntry(appName, GetDisposedMessage());

}

/// <summary>
/// Throw a disposed exception, with explanation.
/// </summary>
private void ThrowDisposed()
{

throw new ObjectDisposedException(mOwnerTypeName, GetDisposedMessage());

}

#endregion

}

}


Whew! There's a lot of code there, especially when you comment it thoroughly. So as promised, I'll give you some dissection.

****************************************************************

But before that, let's get to the good news: because MustDispose is so elaborately crafted, it's really easy to use in any class you design to be disposed. Stealing from the example code above, let's look at a class that must be disposed:

public class DisposableClass : IDisposable
{

// The single MustDispose.
private MustDispose mDispose = new MustDispose( true , true , "This object holds a brush, which must be released back to Windows when no longer needed." );

// The brush that we must release when we're done.
protected Brush mBrush = null;

// The color.
private Color mColor = Color.White;

// The color. We will always create a matching brush.
public Color Color
{

get
{

// Note how we use the Test method of the MustDispose
// to verify that we're not disposed yet. It will
// throw the appropriate exception if we ARE disposed.
mDispose.Test();
return mColor;

}
set
{

// Note how we use the Test method of the MustDispose
// to verify that we're not disposed yet. It will
// throw the appropriate exception if we ARE disposed.
mDispose.Test();
mColor = value;
DisposeBrush();
mBrush = new SolidBrush(mColor);

}

}

// Clean up the brush.
private void DisposeBrush()
{

// Note that we DON'T need a call to mDispose.Test() here.
// Since this is a private method, we're going to assume that
// we'll only call it when appropriate.

if (mBrush != null)
{

mBrush.Dispose();
mBrush = null;

}

}

// The Finalizer. Clean up here, if nowhere else.
~DisposableClass()
{

// Call the internal Dispose, as per Wagner.
Dispose(false);

}

// The internal Dispose, as per Wagner.
protected virtual void Dispose(bool disposing)
{

// Ask the MustDispose whether it has been disposed yet.
if (!mDispose.Disposed)
{

if (disposing)
{

DisposeBrush();

}

}

// Dispose the MustDispose. VERY IMPORTANT! Otherwise, the
// MustDispose will falsely report resource leaks.
mDispose.Dispose();

}

// The standard Dispose implementation, as per Wagner.
public void Dispose()
{

Dispose(true);
GC.SuppressFinalize(this);

}

}


A lot of what you see there is just a robust Dispose() implementation, as described in Bill Wagner's book; and much of the rest is an example of grabbing and managing a resource (a Brush, in this example). The only place where the MustDispose comes into play is these sections:


// The single MustDispose.
private MustDispose mDispose = new MustDispose( true , true , "This object holds a brush, which must be released back to Windows when no longer needed." );


To use a MustDispose, start by creating it as part of initializing or constructing your class.


// Note how we use the Test method of the MustDispose
// to verify that we're not disposed yet. It will
// throw the appropriate exception if we ARE disposed.
mDispose.Test();


We put a call to mDispose.Test() at the start of each method. If the MustDispose has been disposed (and hence this object has as well), an ObjectDisposedException will be thrown, as required by the Dispose Pattern.


// The internal Dispose, as per Wagner.
protected virtual void Dispose(bool disposing)
{

// Ask the MustDispose whether it has been disposed yet.
if (!mDispose.Disposed)
{

if (disposing)
{

DisposeBrush();

}

}

// Dispose the MustDispose. VERY IMPORTANT! Otherwise, the
// MustDispose will falsely report resource leaks.
mDispose.Dispose();

}


Note how, rather than maintain a separate boolean flag in the owner object, we simply ask the MustDispose to determine whether we have been disposed yet. Note also that the last thing our Dispose must do is dispose the MusDispose.

So really, using a MustDispose is quite easy:


  1. Create it as part of initializing your disposable class.

  2. Test it whenever you want to ensure that your disposable class has not yet been disposed.

  3. Use it as a boolean flag for whether your disposable class has been disposed yet or not.

  4. Dispose of it when you dispose of your disposable class.



When you use MustDispose in these ways, it will automatically detect when you try to use an already-disposed object; and just as important, it will scream like a banshee when a disposable object is finalized instead of disposed. Most likely, that will all happen as the app is shutting down. If your client developers have been particularly sloppy, they (or your testers, or your customers) will probably get a slew of messages at app shutdown. They may also occur while running the app, but that's up to the .NET garbage collector: it finalizes objects when it decides to, and you have little say in the matter. (Again, see Bill Wagner's book.)

****************************************************************

So the tricky part, then, is in MustDispose. Let's dissect that, or at least the high points:


/// <summary>
/// Simple constructor. Sets the type name.
/// </summary>
public MustDispose()
{

mOwnerTypeName = GetUndisposedTypeName();

}


The simple constructor reads the owner type name, as described below. The other constructors add functionality to the simple constructor.


/// <summary>
/// The internal Dispose, as described in Wagner's Effective C#.
/// The purpose of the internal Dispose is to have a Dispose with chaining up an
/// inheritance hierarchy, via virtual and override. This class is a root class,
/// so does not need to chain up. At this time, there are no derived classes;
/// but we're allowing for the possibility.
/// </summary>
/// <param name="disposing">
/// True if this was called as part of an IDisposable.Dispose call; false if this
/// was called as part of a finalizer.
/// </param>
protected virtual void Dispose(bool disposing)
{

// Multiple Dispose calls must be nondestructive.
if ( !mDisposed)
{

// We're disposed now. We need to set this flag RIGHT NOW. Otherwise, if we get
// some sort of exception below, we'll fail the Dispose Pattern rule that
// multiple Dispose calls must be non-destructive. That's actually not very
// likely to be a problem (because any exceptions are only likely to occur
// during finalization and Dispose calls after that are highly unlikely); but
// better safe than sorry.
mDisposed = true;

// If we're called as part of a finalizer and we haven't been disposed
// yet, that's a problem. The owner object expected to be disposed, dang it!
if (!disposing)
{

// First, assert that we're disposing. Then possibly take harsher measures.
System.Diagnostics.Debug.Assert(disposing, GetNotDisposedMessage());
// Throw an exception, if expected.
if (Throw)
{

ThrowNotDisposed();

}

// Log an event, if expected.
if (Log)
{

LogNotDisposed();

}

}

}

}


The internal Dispose really isn't all that complicated. It says simply: "If we're being finalized, assert that that's a problem. Also log and throw an exception, if so instructed."


/// <summary>
/// Get the type name of the object which was not disposed.
/// </summary>
/// <returns>The type name.</returns>
private string GetUndisposedTypeName()
{

try
{

// We're going to use System.Diagnostics and System.Reflection
// to find the owner object. Start by getting a stack trace.
StackTrace st = new StackTrace();

// Walk the stack, looking for a type other than MustDispose.
// That will be the owner type.
Type tThis = this.GetType();
for (int i = 0; i < st.FrameCount; i++)
{

// Get the stack frame and the method.
StackFrame sf = st.GetFrame(i);
MethodBase m = sf.GetMethod();

// Compare to MustDispose.
if (m.DeclaringType != tThis)
{

return m.DeclaringType.Name;

}

}

}
catch
{
}

// Never found an owner.
return this.GetType().Name;

}


This function is the key. I wanted MustDispose to find the owner name by itself, without having to be passed it as a parameter. Why? Two reasons:


  • The class name might change during refactoring (or less structured maintenance). I didn't want the connection between the real name and the reported name to be "brittle".

  • Sure as shootin', somebody's going to be too lazy to type the line of code that creates a MustDispose, and will just copy-and-paste it from another class. (Me!) And when they do, if there's a name parameter required, sure as shootin' they're gonna forget to change it. (Me again!) And then the whole purpose of MustDispose will be weakened: it will report that you failed to dispose, but it will report the wrong thing was undisposed.



So instead, I used System.Diagnostics to get a stack trace, and then walked it backwards using System.Reflection to compare types until I found a type other than MustDispose. That is, naturally, the owner type.

The only downside to this approach is security. I'm no code access security expert; but I have to believe there are times when the System.Diagnostics or System.Reflection operations that I use are restricted. More research is called for there.


/// <summary>
/// Log a not-disposed exception, with explanation.
/// </summary>
private void LogNotDisposed()
{

string appName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
EventLog.WriteEntry(appName, GetDisposedMessage());

}


For a very simplistic way of identifying the app in the Event Log, I used Process.GetCurrentProcess().MainModule.FileName. That may also present some security problems. Again, more research is needed.

****************************************************************

That's the code: how to use MustDispose, and how it works. But there's one missing piece of the solution here: the MustDispose process.

What you're going to have to decide in your code is when to use MustDispose, how "loud" to make the messages, and what do you do about them? Do you turn them up really loud, and then have testers refuse to approve a build that has MustDispose errors? Do you make them really quiet and ship the code anyway? I can't make those calls for you. I've given you the tools, but now you have to decide how to use them.

****************************************************************

So that's it. I do agree with Richard that failure to dispose is a problem; I disagree that it's a problem peculiar to the using statement. It's a problem with resource management and disposal in general. And nothing can make disposal automatic, it seems, no matter how hard we try. But with the proper use of MustDispose, it's at least easier to detect and diagnose when you have disposal failures.

Remember what I said?


I disagree with him; but it will take time and sleep before I can fully explain why.


I wasn't kidding!

Monday, January 16, 2006

Laughed so hard, the people at Kinko's are looking at me funny!
(Well, funnier than usual...)

Go here, and go to the item, "Inflation Is on the Rise". I expected an economics story. Then I expected an automotive story. And then I was laughing uncontrollably.

Tuesday, January 10, 2006

Lie. Cheat. Steal. Anything you have to do to win.
I picked up a copy of computer Diplomacy over the holidays. It's a nice implementation, but it's really easy to beat. The AI engine knows tactics, but it's weak on strategy and consequences. Yes, the game will make interesting alliances, and will cheat you if it sees a good chance; but it just doesn't have any long-term vision. Once you get large enough to be a threat, it seems like none of the computer players are smart enough to stop backstabbing each other, while you just keep getting stronger; and at the same time, none of your computer allies are smart enough to decide to abandon you as long as you keep helping them in minor ways. At least some human players would forego temporary gain to stall a growing power, and at least some human players would recognize when they were likely to be your next victim and ought to preemptively attack you.

All I know is that aside from beginner's luck in my first game, I've never outright won a game of Diplomacy against human players; but I beat the computer four games in a row, the last two on the highest difficulty setting.

The game includes an online play option, including a server where you can sign up for games. Maybe when I have a spare day (ha!), I should find a comfy spot with a high speed connection and try to get into a game with some less predictable human players.

UPDATE: Replaced the link, since the one I typed in from the back of the box didn't work. Serves me right...

Wednesday, January 4, 2006

Prime Directive -- Not!
Professor Reynolds links to this very lengthy essay on cultural contamination, and how that may not be as bad as some people want you to believe, by Kwame Anthony Appiah. There's far too much good content here for me to summarize, so I'll just pull out what I think is the most critical point:


So liberty and diversity may well be at odds, and the tensions between them aren't always easily resolved. But the rhetoric of cultural preservation isn't any help. Again, the contradictions are near to hand. Take another look at that Unesco Convention. It affirms the "principle of equal dignity of and respect for all cultures." (What, all cultures - including those of the K.K.K. and the Taliban?) It also affirms "the importance of culture for social cohesion in general, and in particular its potential for the enhancement of the status and role of women in society." (But doesn't "cohesion" argue for uniformity? And wouldn't enhancing the status and role of women involve changing, rather than preserving, cultures?) In Saudi Arabia, people can watch "Will and Grace" on satellite TV - officially proscribed, but available all the same - knowing that, under Saudi law, Will could be beheaded in a public square. In northern Nigeria, mullahs inveigh against polio vaccination while sentencing adulteresses to death by stoning. In India, thousands of wives are burned to death each year for failing to make their dowry payments. Vive la difference? Please.


I'm currently reading Jack McDevitt's Omega, which involves a sorta Prime Directive situation like in Star Trek: a catastrophe looms for a primitive culture, and the cultural preservationists would rather let the natives die than save them and thus expose them to a more advanced culture. The older I get, the more arrogant the Prime Directive sounds to me: sacrificing people's lives for some supercilious view of "culture" that sounds on awful lot like "keeping the primitives in their place". Kwame Anthony Appiah skewers this notion quite adeptly. His essay is long, but it's well worth your attention.

UPDATE: I just read the credits at the end of the essay. It turns out to be an extract from the author's book, Cosmopolitanism: Ethics in a World of Strangers, coming later this month. Gee, just what I needed: an excuse to shop for books...
Call it a miracle, call it what you want... Crap. Crap, crap, crap, crap, crap.
...I'm just calling it far better news than I predicted 9 hours ago:


SAGO, W.Va., Wednesday, Jan. 4 - Forty-one hours after an explosion trapped 13 men in a West Virginia coal mine here, family members and a state official said 12 of the miners had been found alive Tuesday night.

Earlier Tuesday evening, the body of one miner was found 11,200 feet from the mine entrance, within a few hundred feet of a vehicle used to transport the workers deep into the mine, company officials said. The miner was not identified, and the cause of his death was unclear.

Joe Thornton, deputy secretary for the West Virginia Department of Military Affairs and Public Safety, said the rescued miners were being examined at the mine shortly before midnight and would soon be taken to nearby hospitals. Mr. Thornton said he did not know details of their medical condition.


One man lost is tragic, of course; but after they found his body, I expected to hear about twelve more bodies by the morning. Seldom have I been so glad to be wrong.


UPDATE: Communications breakdown. Instead of one fatality, there's one survivor, who's in critical condition right now.

Seldom have I been so sorry to be right.
Posted in News by Martin L. Shoemaker on Wednesday January 4, 2006 at 2:59am. 0 Comments 0 Trackbacks