Saturday, January 12, 2008

Borrowing Ideas From 3 Interesting *Internal* Classes in the .NET 3.5 Framework To Help Control "Goo" In Your Code

As programmers, we often have to concern ourselves with scaffolding "goo" in our code as in the start of the System.Collections.Queue.CopyTo method:

1 public virtual void CopyTo(Array array, int index)
2 {
3     if (array == null)
4     {
5         throw new ArgumentNullException("array");
6     }
7     if (array.Rank != 1)
8     {
9         throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported"));
10     }
11     if (index <>
12     {
13         throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
14     }
15     if ((array.Length - index) < this._size)
16     {
17         throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
18     }


All of the checking is considered a best practice in our field. We are taught to never trust input and to be paranoid about what get into our functions.

But it took 16 lines!

I'm always on the lookout for how to improve my code writing on gooey areas like this. Recently I was doing some reflectoring into the .NET 3.5 framework and noticed two helper internal classes that the smart folks on the LINQ team created to help get their job done:

Exhibit A: System.Linq.Strings


Our first stop takes us to generating error messages to give to the user. We're told that it's a best practice to always use resources for strings that are visible to a user and this helper class makes it easy to do that so that we can write statements like

"throw new ArgumentException(Strings.ArgumentNotIEnumerableGeneric(p0));"

Doesn't that last line just feel better than something like the CopyTo way of "

throw new ArgumentException(Environment.GetResourceString("ArgumentNotIEnumerableGeneric"));
"? Furthermore, it helps to insulate you from the ramifications of renaming a resource. It also lets you use IntelliSense while writing code and lets you use easily refactoring tools if you want to change the name later.

Exhibit B: System.Linq.Error


The team went one further and created another helper class to create error messages based off the Strings class as in:

internal static Exception ArgumentNotIEnumerableGeneric(object p0)
{
   return new ArgumentException(Strings.ArgumentNotIEnumerableGeneric(p0));
}

Once you have this class, you can now have lines like this one from the System.Linq.Queryable.AsQueryable method:

if (type == null)
{
     throw Error.ArgumentNotIEnumerableGeneric("source");
}

To me, that looks much more readable/declarative/maintainable/fluent than how Queue.CopyTo does the same type of thing.

This comes to the limit of where the Linq team took it and which brings us to the final internal class of note.

Exhibit C: Microsoft.Contracts.Contract

The Contract class has some interesting use in 3.5 classes as in a constructor of (the unfortunately also internal class) System.Numerics.BigInteger:

3 Contract.Requires(_data != null);
4 Contract.Requires((_sign >= -1) && (_sign <= 1));
5 Contract.Requires((_sign != 0)  (GetLength
 
This is a bit more declarative than the Linq way, but also achieves roughly the same goal since Requires has this implementation:

1 public static void Requires(bool b)
2     {
3         if (!b)
4         {
5             throw new PreconditionException();
6         }
7     }


It seems that if we combined the best of both of the ideas from the two teams, we'd get something like this:


1 internal static class Guard
2 {
3     internal static void ArgumentNotNull(object value, string paramName)
4     {
5         if (value == null)
6         {
7             throw Error.ArgumentNull(paramName);
8         }
9     }
10 }

This allows for this usage: "Guard.ArgumentNotNull(data, "data");" which would throw the correct exception. Now, anywhere in your code where you want to require that an argument isn't null, you simply call this method. As an added benefit, by right clicking on the "ArgumentNotNull" method in Visual Studio, you can find all references to see where you had to do that check in your code. Better still, is that you fall into the Pit of Success of doing the right thing by doing less work!

You could use something like the Enterprise Library's Validation Application Block to achieve similar results, but the "Guard" approach seems very simple and especially useful when you can't use other libraries for one reason or another.

It's clear that Microsoft.Contracts.Contract was inspired by the Spec# project as seen in the attributes and method bodies of some methods like "Invariant":

1 [Pure, Conditional("USE_SPECSHARP_ASSEMBLY_REWRITER")]
2 public static void Invariant(bool b)
3 {
4   string text1 = "This method will be modified to the following after rewriting:" + "if (!b) throw new InvariantException();";
5 }


I believe that C# 4.0 (or possible 5.0) will bring in Spec#'s ideas to the masses to allow for things like:

1 class ArrayList 
2 { 
3     void Insert(int index , object value)
4         requires 0 <= index && index <= Count otherwise ArgumentOutOfRangeException;
5         requires !IsReadOnly && !IsFixedSize otherwise NotSupportedException;
6         ensures Count == old(Count) + 1;
7         ensures value == this[index];
8         ensures Forall{int i in 0 : index ; old(this[i]) == this[i]};
9         ensures Forall{int i in index : old(Count); old(this[i]) == this[i + 1]};
10     {
11         ...
12     }
13 }

All of which will surely make code more reliable through static analysis if used correctly.

At the very least, it's good to see the gems tucked away in the internal classes of the framework to see how things like Strings, Error, and Contract/Guard can make even your C# 2.0 code look better.

What do you think? What types of helper classes do you use to make your code have less "goo?"

UPDATE: Thanks to "Tweezz" in the comments for pointing out the general idea for Guard goes back to Eiffel's trademarked "Design by Contract" philosophy.

UPDATE 2: The internal class System.Data.ExceptionBuilder does the same thing as System.Linq.Errors, but doesn't punt to a Strings equivalent class.

UPDATE 3: Andrew Matthews has some interesting applications of Design by Contract using C# 3.0. Check it out here.

kick it on DotNetKicks.com

P.S. Thanks to my coworker, Dan Rigsby, for introducing me to the "Guard" class idea!

9 comments:

TweeZz said...

This is the one I'm using. It's the guard principle...: Design by contract.
http://www.codeproject.com/KB/cs/designbycontract.aspx

ps: Your blog doesn't show correct in FF..

Jeff Moser said...

tweez: Thank you very much for your comment!

I hadn't seen the link you mentioned before. It seems that the author of that one had similar goals. I like the idea of possibly adding a "Guard.ArgumentEnsure(bool condition, string paramName, Exception exceptionToThrowIfConditionFails)" with a simplified verision that just throws an ArgumentException.

Thanks for letting me know about things not showing up well in FireFox. I manually edited the HTML to add a border around the code. I'll do a bit more searching on how to best render code. I have been using the "Copy Source as HTML" plugin, but there's probably a better way.

Anonymous said...

Interesting stuff.

A thought occurred to me while reading through this. What if we could decorate our parameters for common scenarios such as nulls. To guard against a null reference you could use a suffix in a similar way to how ? can be used for nullable value types.

For example, let's use an exclamation point to guard against null parameters:

public virtual void CopyTo(Array! array, int index) { ...

So if array is null it would throw an exception.

Taking this a bit further, a double exclamation could guard against null or empty strings:
public virtual void Foo(String!! myString) { ...


Not saying this is a good idea, just that it's interesting to think about.

Phil

Jeff Moser said...

Phil: this is more or less the idea that Spec# brings. It seems that the Eiffel folks have been doing this for years in terms of the "requires"/"ensures" pattern.

After reading more on Design by Contract and looking at Spec#, a cool glimpse of the future came into my mind. Detecting bad parameters at compile time.

It's not much of a leap to go from (to use your example)

public virtual void CopyTo(Array! array, int index) {...}

to looking at the call sites like

al.CopyTo(null, 0)

and throwing a compile time error saying that this violates the contract. That is really cool stuff.

You might also want to check out Wes's support for specifications via statements embedded in comments in his upcoming NStatic tool.

Andrew Matthews said...

Hi Jeff,

Thanks for a very interesting and worthwhile post. And thanks also for your related comments at my blog (to which I replied BTW).

These classes definitely look like placeholders to help with assembly re-writing tools (which I presume is what Spec# is, considering the Conditionals on some of the methods).

Even if the classes were publicly accessible, they wouldn't be truly DBC because they lack two critical components of DBC: inheritable constraints and before/after comparisons that allow you to confirm that you upheld your end of the contract.

Inheritable constraints are what's missing from the implementation I blogged about, and it's a major flaw, because you only have to override one of my methods to be freed from all the constraints I placed in my original class or interface.

I'm still looking for a way around the 'no lambdas or generics in attributes' restriction on .NET 3.5. If you find a way round it, let me know!

Cheers

Andrew Matthews

Greg said...

Jeff wrote:

"t's not much of a leap to go from (to use your example)

public virtual void CopyTo(Array! array, int index) {...}

to looking at the call sites like

al.CopyTo(null, 0)

and throwing a compile time error saying that this violates the contract. That is really cool stuff."


You do realize spec# already does *exactly* this ... the "boogie" portion of spec# is a full theorem prover and does give errors at compiler time.

Cheers,

Greg

Jeff Moser said...

Greg: Thanks for the info! I hadn't actually tried running spec# with an error, but it's good to know.

I'm also curious how far Boogie's help goes with projects like Pex. Something like Spec# for compiler errors and Pex/Boogie for warnings.

Greg said...

spec# errors (through boogie) can also show up as warnings ... its just a matter of enabling it in your project...

To do this right click on your project and go to properties ... then go to build ... under misc there is an item called "RunProgramVerifier" it is set to false by default, set it to true and off you go.

You might also want to try RunProgramVerifierWhileEditting which will incrementally run it and give you squiggly lines while you type.

Jeff Moser said...

Greg: very interesting! Thanks for the info. I'll have to try it out.