Friday, 08 June 2007
It seems every 3 years or so I need to be slapped upside the head and reminded that in SQL Server...

record order in a result set is not guaranteed unless you use ORDER BY

So I don't have to be hit in the head again, I'm writing it down.

The issue is that:
frequently the results ARE returned in order of entry
and
frequently developers start assuming that will always be the case
and
frequently developers build code based on that assumption.

Months go by.

Then a subtle bug occasionally appears and someone spends the better part of an evening trying to replicate the bug, and finally generates mostly, but not entirely correct results.  By all appearances nothing is missing, but the code is angry when prodded just so.  Running the underlying stored procedure in Query Analyzer reveals that the records being returned are slightly out of order. The relevant SELECT statement lacks an ORDER BY clause.  The clause is added.  The records are returned in the expected order.  The code is happy.  The developer can go to sleep.

Friday, 08 June 2007 09:40:53 (Eastern Standard Time, UTC-05:00)   #     Comments [1]  | 
Tuesday, 05 June 2007
I hate writing the same code twice.  Not just because I am a horrible typist, but because writing the same code twice means testing it twice, debugging it twice, maintaining it twice, etc.  I recently ran into a situation where this looked unavoidable.  I needed to write (a little more than) a wee bit of code that evaluated values against arbitrary conditions in the same way.  The twist was that these conditions could have different types. 

I didn't want to duplicate the code for each type. However, I also wanted it to be strongly typed, so I didn't want to resort to using the object type for everything.  Since all the types in question are numeric, I could have simply coerced everything into a decimal or a double type and written the bulk of the code against that one type.  But I didn't like this for three reasons:
  1. It would be imprecise: I wanted to compare integers to integers when I could
  2. It would require adding a layer of conversion logic
  3. It just didn't feel right.  It wasn't elegant.
Not all code is elegant, but it seems to flow much more easily and get working more quickly when it is.  So while I was counting up the types I'd need to support and contemplating the heinous sin of cut and paste coding, it occurred to me that .NET 2.0 should allow me to solve this very elegantly, using Generics

I have already fallen in love with the generic collections and have kicked the ArrayList to the curb, so it was time to figure out how to make a generic class of my own devising.

The <T> is the key...

public class OneRuleToBindThem<T>

This tells the complier that the class will be created for the specified type in <>.

So I whipped up my first generic class. The simplified version looked vaguely like this....

public class OneRuleToBindThem<T>
{
    private T mMinimumValue;
    private T mMaximumValue;
    private const string PASS = "Pass";
    private const string FAIL = "Fail";

    public OneRuleToBindThem(T MinimumValue, T MaximumValue)
    {
        mMinimumValue = MinimumValue;
        mMaximumValue = MaximumValue;
    }

    public string Evaluate(T ObservedValue)
    {
        string Result = PASS;
        if (ObservedValue > mMaximumValue)
            Result = FAIL;
        if (ObservedValue < mMinimumValue)
            Result = FAIL;

        return Result;
    }
}



That was too easy!  Let's compile it and move on...

Operator '>' cannot be applied to operands of type 'T' and 'T'  

What in the la-di-da does that mean? Shazbot.  Why can't I compare a T with a T?  They'll be the same type for pete's sake.  A little googling and reading and OK, the compiler doesn't know if a supplied type will support the given operand, so it properly throws an error.  Surely there must be a way around this, some way to reassure the compiler that only appropriate types will be used, really!

A hint from Ryan Olshan led me to check out IComparable. Ah, it is possible to constrain the types that can instantiate the class.  So I tried...

public class OneRuleToBindThem<T> where T:IComparable
{
//code you've seen before...
}

Compile and...the same errors appear in the build.  Fudgesticks.

An idea flickered.  Since I would only be using types that implement IComparable, maybe I could use the interface's CompareTo method somehow.

So, I rewrote the Evaluate method...

public string Evaluate(T ObservedValue)
{

       string Result = PASS;
        if (ObservedValue.CompareTo(mMaximumValue) > 0)
            Result = FAIL;
        if (ObservedValue.CompareTo(mMinimumValue) < 0)
            Result = FAIL;

        return Result;
    }

F5 to compile and -- hoorah.  The darn thing works, well compiles anyway.  Let's see if it actually works with a little test code...

        OneRuleToBindThem<int> AnIntegerRule = new OneRuleToBindThem<int>(4, 10);
        for (int Index = 1; Index <= 11; Index++)
        {
            Debug.WriteLine(String.Format("{0} : {1}", Index, AnIntegerRule.Evaluate(Index)));
        }

        OneRuleToBindThem<decimal> ADecimalRule = new OneRuleToBindThem<decimal>(4, 10);
        for (decimal Index = 1M; Index <= 11M; Index+= 0.2M)
        {
            Debug.WriteLine(String.Format("{0} : {1}", Index, ADecimalRule.Evaluate(Index)));
        }


Good golly.  Worked on the first, ahem, try.  Now is the time on "OOP - There it Is" when we dance.

Granted the example Evaluate method is only a few lines of code (and could be slimmer). In this example it wouldn't be too onerous to store the MinimumValue and MaximumValue as doubles, and then write an overloaded Evaluate method for each type using the appropriate convert functions.  But when Evaluate is 20+ lines of code and the class needs to support 3+ types, that's a shameful amount of cut-and-paste code. Shameful.

But with the Generic implementation, everything is strongly typed. And best of all, there's only one method to test, debug and maintain! Once again, my fear of typing led to a sweet little implementation.

Tuesday, 05 June 2007 22:46:14 (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 

Theme design by Dean Fiala

Pick a theme: