Wednesday, December 3, 2008

null is not a boolean

One coding practice I have a problem with is returning null to signify "no value here". This leads to null-check-littered code ans consequently decreases readability. Davy Brion has elaborated on this subject here and I can only agree wholeheartedly.

So, how do we deal with data that may or may not be present?

If possible, the best approach is to use the null object pattern. This allows the calling code to completely ignore the fact that the object is undefined. I'll not write anything more about it, check the web for more information.

There are however cases where the caller actually need to know if there is a value present or not. Consider the following code:
class Person
{
public Animal Pet { get; }
}
In this example, a person may or may not have a pet. If we use null to signify the absence of a pet then code that accesses a Person object would have to write code like:
void WritePet(Person person)
{
if (person.Pet != null)
{
Console.WriteLine("Pet name is: " + person.Pet.Name);
}
}
The first issue with this code is the "person.Pet != null" check. We're using the Pet reference do the extra work of keeping track of if there is a value present or not. The Pet property should be used to access the Pet, not to determine wither there is a value there or not.

The second issue is that nothing in this code indicates that null is a valid value. You could add this information in a comment but relying on comments should be avoided when possible.

I prefer the following construction:
class Person
{
private Animal pet = null;
public bool PetIsValid { get { return pet != null; } }
public Animal Pet { get { return pet; } }
}

Yes, this adds a bit of code to the class. And yes, I'm using the pet field as a boolean myself. The difference though is that I only perform the pet != null check internally in the class. It is not unreasonable for the class to know that the pet value may be null.

We can now rewrite the calling code as:
void WritePet(Person person)
{
if (person.PetIsValid)
{
Console.WriteLine("Pet name is: " + person.Pet.Name);
}
}

The first benefit of this pattern is that the calling code is simply more readable. (Yes, that is subjective.)

A second and more important benefit of applying this pattern consistently in a code base is that when you find a property that does not have an associated XyzIsValid property you can be sure that it will not be null!


(A small note on the naming: I think that HasPet would be a better name than PetIsValid. The drawback is that it would be harder to discover. Using the PetIsValid naming convention this method will appear in the intellisense list when you type person.Pet, hinting that you should probably check validity before proceeding).

Thursday, October 9, 2008

Running MSBuild tasks programmatically

I tried scouring the web for a description on how to run MSBuild tasks from your own code but came up with slim results. After some investigations this is one way that managed to run some tasks at least.

For this example, we'll compile a .cs file in the simplest way possible. To achieve this we need to use the Csc task.

There is one property on all tasks that deserves a special mention. It is Task.BuildEngine. The property is of type IBuildEngine and as far as I can tell the only implementation of this interface is an internal class called EngineProxy in the Microsoft.Build.BuildEngine namespace. Since it's internal we cannot use it.

We need to create our own IBuildEngine implementation. It turns out that this is pretty straightforward:


public class MyBuildEngine : IBuildEngine
{
public bool BuildProjectFile(string projectFileName, string[] targetNames,
IDictionary globalProperties,
IDictionary targetOutputs)
{
throw new NotImplementedException();
}

public int ColumnNumberOfTaskNode
{
get { return 0; }
}

public bool ContinueOnError
{
get { return false; }
}

public int LineNumberOfTaskNode
{
get { return 0; }
}

public string ProjectFileOfTaskNode
{
get { return ""; }
}

public void LogCustomEvent(CustomBuildEventArgs e)
{
Console.WriteLine("Custom: {0}", e.Message);
}

public void LogErrorEvent(BuildErrorEventArgs e)
{
Console.WriteLine("Error: {0}", e.Message);
}

public void LogMessageEvent(BuildMessageEventArgs e)
{
Console.WriteLine("Message: {0}", e.Message);
}

public void LogWarningEvent(BuildWarningEventArgs e)
{
Console.WriteLine("Warning: {0}", e.Message);
}
}
This implementation is very simple.
  • We'll simply ignore BuildProjectFile since we're running tasks manually here.
  • The *TaskNode methods are also almost ignored. I haven't investigated them but it looks like they're used for reporting errors in project files.
  • The Log* methods simply dump the message to the console.
Now we're ready to run the Csc task:


Csc cscTask = new Csc();
cscTask.BuildEngine = new MyBuildEngine();
cscTask.Sources = new TaskItem[]{
new TaskItem(@"C:\Code\Projects\MSBuildTest\HelloWorld\HelloWorld.cs")
};

if (cscTask.Execute())
{
Console.WriteLine("Task executed ok. Resulting assembly: {0}",
cscTask.OutputAssembly
);
}

This will produce an output file HelloWorld.exe in the working directory.

Obviously, there are lots of other properties available on the Csc task but this was just the simplest example possible.

Monday, October 6, 2008

BuildLib

I initiated yet another side project this weekend. It's an idea that has been growing on me for a while.

A build engine that uses C# as a scripting language.

The recipe for a build frequently includes a number of tools. A few utility .exes here, some .bat files there. A bit of scripting in NAnt or MSBuild. Maybe even some custom extensions to the build engine. Finally, a little continuous integration scripting to finish it all off.

Wouldn't it be neater to unify this into one tool?
Why should I need to learn yet another syntax (i.e. Nant or MSBuild)?
Why create clumsy custom language using XML when C# is more powerful then msbuild will ever be?

Imagine that you want to have a file that contains a simple timestamp. Something along the lines of:
namespace MyProject {
public class BuildInfo {
public string BuildDate = "_BUILDDATE_PLACEHOLDER_";
}
}

And you want to transform this into:
namespace MyProject {
public class BuildInfo {
public string BuildDate = "2008-10-07";
}
}

How would you update this using msbuild? My best bet is that you would need to obtain and include MSBuild community tasks and use FileUpdate task. I have no idea how to obtain a properly formatted date...

Compare this to:
string templateText = File.ReadAllText("BuildDate.cs.template");
string buildDate = DateTime.Now.ToShortDateString();
string updatedText = templateText.Replace("_BUILDDATE_PLACEHOLDER_", buildDate );
File.WriteAllText("BuildDate.cs", updatedText);

To solve some of these issues I initiated a project with the boring yet appropriate name BuildLib.

So, what is the current state of BuildLib?
  • It has a name! That took me a good two hours.
  • It has project page on google code.
  • It has stub projects and a directory structure (heavliy influenced by JP Boodhoos post)
I'll try to use this blog as a design diary for BuildLib. We'll see where the project heads. Perhaps it will turn out to be a fluent interface over MSBuild, a full fledged build engine or (perhaps most likely) yet another abandoned side project that got 60% done.

Since I have a 8 week old girl at home I don't expect any abundance of free time. On the other hand, she normally wakes me up at 6 in the morning so I do have an hour or two before work...