As covered in part one I have decided to create a fluent library for validating arguments as I wasn't happy with ones currently available. But what exactly do I want?
.Check() or .Validate() method)Which gives a syntax something like this:
public static void SomeMethod(string stringValue, int intValue)
{
Validate.Argument(stringValue, "stringValue")
.IsNotNull()
.IsNotEmpty();
Validate.Argument(intValue, "intValue")
.IsPositive()
.IsLessThanOrEqualTo(5);
Why have I created a class called Validate with a property called Argument rather than a class called ValidateArgument? This is so I can expand the library to validate other things apart from arguments, all from the same starting point. For example I could expand it to do things like:
public static void SomeOtherMethod<TEnum>(TEnum enumValue, string directory) where TEnum : struct
{
Validate.TypeParameter(typeof(TEnum), "TEnum")
.IsEnum();
Validate.Directory(directory)
.Exists()
.IsEmpty();
So, how am I going to actually code this thing? Well if I'm going to chain these validations together then I will need to store the argument and parameter name somewhere. There are a two obvious ways to do this:
IsNotNull() in a row for example. Therefore we are either going to need to create a new object when the methods in the chain change or create one object that implements multiple interfaces explicitly and then cast it to a different interface when then methods in the chain change. And should our objects be structs or classes?Which way is best? Are any methods intrinsically worse for some reason? Performance is a good reason. Whilst I'm a firm believer that you should get you application working and performance enhance after (slow code is better than no code!) I also think prototyping is a good idea. If we can do a simple test at this stage then we might well find out that one approach is fundamentally slower than the others.
So I've knocked together a simple application to test each method and see which is quickest; feel free to play with the source code. It measures how long it takes to validate a string argument is not not null and not empty 25,000,000 times, compared against two not so fluent methods. On my PC the results are: (times in seconds)
| Method | Description | Debug | Release |
|---|---|---|---|
| Not as fluent, single method | Does both validations in a single call, i.e. IsNotNullOrEmpty(argument, parameterName); |
1.74 | 0.39 |
| Not as fluent, separate methods | Does one method call for each validation, passing in argument and parameter name to each method. | 2.66 | 0.69 |
| Create multiple classes | Creates a new class each time the methods in the chain change. | 6.05 | 2.47 |
| Create single class | Creates a single class and casts it to a new interface each time the methods in the chain change. | 3.00 | 1.00 |
| Create multiple structs | Creates a new struct each time the methods in the chain change. | 3.70 | 1.75 |
| Create single struct | Creates a single struct and casts it to a new interface each time the methods in the chain change. | 3.73 | 1.86 |
| ThreadStatic store | Stores the argument and parameter name in fields marked with the ThreadStaticAttribute; uses extension methods to build the chain. | 7.32 | 4.01 |
| ThreadLocal store | As above but uses a named data slot on the current thread to store the argument and parameter name. | 80.97 | 80.08 |
| ContextStatic store | Stores the argument and parameter name in fields marked with the ContextStaticAttribute. Not at all suitable for the job... It's here for no other reason than I'd not heard of this attribute until recently and wanted to see how it performed... | 50.25 | 51.93 |
So it looks like the single class approach wins. A few things to note though:
So I have an approach. In the next post I'll start to look at implementing it.
I like fluent interfaces. And I'm very pedantic about validating arguments. So I went looking for a fluent interface for validating arguments. And I found a few, but none were quite what I'm looking for. So yup, I decide to write my own.
Before explaining how I did that though I would like to mention a couple of those and explain why they are not what I'm after; hopefully that will help to why I felt the need to write my own.
An excellent article on the Paint.NET blog gives details of one approach. Whilst taking care to optimise for the non-exceptional path (no objects are created unless validation fails) it didn't feel fluent enough for me. An example of the interface given is:
public static void Copy<T>(T[] dst, long dstOffset, T[] src, long srcOffset, long length)
{
Validate.Begin()
.IsNotNull(dst, "dst")
.IsNotNull(src, "src")
.Check()
.IsPositive(length)
.IsIndexInRange(dst, dstOffset, "dstOffset")
.IsIndexInRange(dst, dstOffset + length, "dstOffset + length")
.IsIndexInRange(src, srcOffset, "srcOffset")
.IsIndexInRange(src, srcOffset + length, "srcOffset + length")
.Check();
For me a fluent interface should allow you to specify something, and then let you chain a sequence of operations on that something. jQuery is the an excellent example of a good fluent interface; you specify an element and then perform a chain of actions on that element. For argument validation I would expect us to specify an argument and then chain a sequence of validations on that element. Which is why I don't feel this interface is fluent enough for me. It does not specify an argument at the start, but rather it specifies the arguments each time. Consider the following example of the above style:
public void DoSomething(int? argument)
{
// Check argument isn't null and is between 0 and 100.
Validate.Begin()
.IsNotNull(argument, "argument")
.IsGreaterThanOrEqualTo(argument, "argument", 0)
.IsLessThanOrEqualTo(argument, "argument", 100)
.Check();
Doesn't seem much point to me in chaining the methods if we keep having to specify the argument and parameter name each time.
Of course there are valid reasons for this; if we don't specify the argument and parameter name each time then we are going to have to store them somewhere and that means a tiny performance hit; you're gonna need to set a field or create and object or do something to store that information. For an application like Paint.NET that needs every ounce of performance that could well be a problem.
For my interface I'm willing to take a tiny performance hit to get the interface I want. If I have to create a short lived object or set a field then I'm not too fussed about that to be honest. I find there are a lot of people who would moan about such things. Sometimes for good reason. But more often they'll complain that I should use a byte instead of an int whilst at the same time think that boxing is a sport and an expression tree is a plant that smiles. If I've optimised every other area of my application and actually need to get a bit of extra performance then I'll be a happy man. And I'll just drop the argument check...
Roger Alsing has a good approach. Much more fluent; we only specify the argument once:
public static string ValidationFunc(int a, string b, DateTime c)
{
a.Require("a")
.IsGreaterThan(10);
b.Require("b")
.NotNull()
.NotEmpty()
.LongerThan(2)
.StartsWith("Ro");
I have two main problems with this approach:
a.Require()) so it can be used as a general validation method. But I would prefer to be explicit about the fact that we're validating an argument.b.Require("b").NotNull().NotNull().NotNull().NotNull().NotNull().NotNull();
a.Require("a").IsGreaterThan(4).Require("b").NotNull();.NET Junkie outlines a similar approach. The article talks about the relationship to Spec# which gives some more info on why the interface is created like it is. I just want to validate my arguments in a nice fluent way which are my pre-conditions. As for post-conditions my method code should be doing that!
Awesome but not released yet. 8o)
In the next post I'll start to plan out what I want from the fluent interface and start thinking about the best way to get it.