Monday, September 26, 2011

MSBuild Properties in Delphi

From Delphi 2007 forward the Delphi IDE relies on MSBuild to manage project dependencies, compiler options, etc. If you're a Delphi developer you are likely familar with the $(..) notation used for accessing values exposed by the build system. With a little digging you'll discover some of these values are environment variables and that you can modify them or create your own. If you take a closer look you'll see there are other values accessed using $(..) that are not environment variables.

The $(..) notation comes from the make syntax. It is used for referencing variables defined in a make script. Prior versions of Delphi relied of Borland's variation of make. MSBuild (as well was most other xml based build scripts) inherited certain design ideas from make. The $(..) notation is one of them. In MSBuild variables are called properties. Delphi's .dproj files are simply MSBuild files with a little customization.

MSBuild treats environment variables and property values within a build script the same. This is why you can access environment variables using $(..). You can also create enviroment varibles that override properties in a project file. So what properties are defined?

Take a look at BDS\Bin\*.Targets. Every .dproj file you create includes one or more of these .targets files. Every option passed to the compiler has an associated property that can be accessed at various stages of the build process. You can take advantage of these for setting the output path for generated files and writing pre and post build scripts. Be careful not to modify the supplied targets files. You are free to define your own targets files and incorporate them into your projects. I may write a separate article about custom targets at a later time.

Example
Its common to want debug and release artifacts to output to separate folders. You can edit each configuration to output to ".\debug" and ".\release" or you can just edit the base configuration instead:

Output directory = $(Config)

Now any configuration inheriting from the base configuration will use the Config property when writing the executable to disk. You can create additional configurations that inherit from Base and they will override the Config property with their name.

Tuesday, August 30, 2011

The "With" Statement

Regardless of which language you use the controversial with statement's intended purpose is to reduce repetitive typing. Some developers think its the greatest thing since sliced bread. Others are certain it was created by Satan. Let's examine a few languages that support it.

Pascal

The with keyword was present in the original Pascal language, developed in 1968-70 and published in Acta Informatica, Vol. 1 in 1971. I've found no description of a with statement in Wirth's prior language projects or in any of the languages which influenced Pascal's design. Though admittedly, my research into its origins is limited. I'll assume for the moment that it was an original idea.
The with statement was originally intended to only be used with record variables. Here's a modification of a sample record from the original language description.

type
  Date = record
    day: 1..31;
    month: 1..12;
    year: 0..9999;
end;

var
 today: Date;
The two following blocks are equivalent:
begin
  with today do
  begin
    day := 25;
    month := 12;
    year := 2011;
  end;
end;

begin
  today.day := 25;
  today.month := 12;
  today.year := 2011;
end;

Object oriented descendants of Pascal added support for classes and interfaces. The main criticism of with is that it introduces the possibility of ambiguous references:
var  day: integer;  
  today: Date;

begin
  with today do
  begin
    day := 25;
    month := 12;
    year := 2011;
  end;
end;


Which day is being assigned to? Intuition may lead you to think that it is the one within the scope of the date record and you'd be right, at least in this case. However, when this block is in the body of an object method, which references multiple other objects in the same with statement it isn't so clear.

Where things really fall apart is when you are referencing a local variable from within the body of a with statement and a field or property with the same name is added to the definition of the object or record referenced by the with statement. Suddenly code that was working flawlessly fails and all you did was add a field to a class definition. Heck, you haven't even referenced the new field in your code yet... or so you think.

So that's Pascal's implementation. I would recommend you avoid using it whenever possible and use great care if you find it necessary to use it. What other languages support the with statement? Let's take a look.

VisualBasic


With today
  .day = 25
  .month = 12
  .year = 2011
End With

Here we see dot notation preceding the fields. This makes it apparent which identifiers are fields and which are not. This syntax was carried forward into VB.NET as well. There is still the possibility of ambiguity if you write a nested with statement. According to the documentation the compiler would only see the fields of the object referenced by the inner with statement until the statement's end. A novice developer could easily overlook this.

JavaScript

JavaScript's with statement functions more or less the same as Pascal's and JS developer's opinions of it are just as polarized as Pascal developer's. ECMAScript 5th Edition "Strict" mode forbids its use and many implementations now emit a warning that it has been deprecated and/or suggest an alternative.

D

Digital Mars' D language supports a with statement with behavior similar to Pascal's with one notable exception: local identifiers and identifiers within the scope of the with statement cannot have the same name. This results in a compilation error, effectively preventing the ambiguity caused by the introduction of new object members.


struct Date
{
    int day;
    int month;
    int year;
}

void main()
{
    int day;
    Date today;
    with (today)
    {
        day++;  // error, shadows the local day declaration
    }
}

Languages with similar features

These languages have similar features but the purpose and/or syntax is too different for them to be consider the same as with.
  • Smalltalk cascades - multiple messages can be sent to the same object separated by a semicolon
  • C#
    • using statement - encapsulates the more verbose try..except..finally syntax when working with implementors of IDisposable
    • object and collection initializers - a more concise syntax for setting object properties at creation time
  • Python with statement - similar to C#'s using statement, it encapsulates the try...except...finally pattern into a less verbose syntax.

Fluent Interfaces are another programming style that can be used to accomplish the same goal as with statements. They use varying combinations of method chaining, nested functions and object scoping along with careful method naming to produce concise, readable statements. The Date record could be rewritten as:
type
  Date = class
  private
    FDay: 1..31;
    FMonth: 1..12;
    FYear: 0..9999;
  public
    function Day(Day: integer): Date;
    function Month(Month: integer): Date;
    function Year(Year: integer): Date;
  end;

function Date.Day(Day: integer): Date;
begin
  self.FDay := Day;
  Result := Self;
end;

function Date.Month(Month: integer): Date;
begin
  self.FMonth := Month;
  Result := Self;
end;

function Date.Year(Year: integer): Date;
begin
  self.FYear := Year;
  Result := Self;
end;

Then in place of the with statement you could write:
begin
  today := Date.Create
               .Day(25)
               .Month(12)
               .Year(2012);
end.

Monday, December 20, 2010

A case for testing getters, setters and properties.

Conventional wisdom suggests that getters and setters (a.k.a. properties) are simple enough that testing them is unnecessary unless some branching logic has been introduced. This is advocated in any number of books on the subject of unit testing. This is what I thought as well. After all, most properties simply assign and retrieve a value without any manipulation.

Today I discovered a reason that may make it worth while to test even these. I spend most of my time working with legacy code. Often times I am uncomfortable making changes without the safety of a test harness so I'll take advantage of automatic test generation to create skeleton tests from production code that I can fill in as I work.

The tool I use for this isn't terribly smart. It just creates a class of test cases for each public method it finds in the production class its given. Each test case calls each method but leaves the Assertion up to the developer to fill in.

I had just created a new test harness from a production class I needed to modify. I ran the tests without any changes, meaning no checks were being done. I fully expected the tests to succeed since the framework I was using didn't consider an assertion-less test to be a failure. I was amazed when it did in fact fail.

The reason for the failure was a stack overflow caused by a getter returning the value of the property it was as a backing function for rather than the value of the backing field. This of course resulted in an endless recursion that quickly exhausted the call stack. This bug had never turned up in production because this was a base class that wasn't used directly and all descendant classes overrode that particular getter.

This subtle bug is more likely to happen in languages like C#, Object Pascal and Python (and several others) which hide the getter and setter calls behind a more friendly syntax that allows them to be assigned like public fields.

MyObject.PropertyValue = 123;

So even before any of the tests were verifying results they had already uncovered a bug in one of the simplest operations possible.

Friday, August 20, 2010

Bad Programming Practice #2

Misusing CTRL+V

It seems innocent enough. You write a snippet of code that causes tulips to spring up all over the computer screen. The users rejoice. Some time later they decide they want the option to see sunflowers as well. They're both flowers and your time is precious so you decide the quickest way is to copy the tulip code, and replace tulip with sunflower. Problem solved. The users rejoice again.

The years pass. Each time the users request another type of flower: CTRL+C, CTRL+V, Modify. Then one day... you discover your original tulip desktop function has the ugly side effect of slowly filling the user's hard drive with temporary files in random locations until it chokes. Only now you have 500 modifications of the same function, many of which barely resemble the original and they all have the same problem. It takes months to fix and even after you release Flower Desktop 10.0 SP1 you're still not sure if you found them all. Mean while, your users grow tired of manually hunting for randomly placed temporary files while waiting for you to fix the problem and decide to replace your program with the cool new Flaming Desktop 1.0 they just finished downloading. You flog yourself repeatedly for copying and pasting to save time when it would've only taken slightly longer to modify your tulip function to take the type of flower as a parameter. Saving you all this work hunting down evil clones of ShowTulips().

Wednesday, August 18, 2010

Bad Programming Practice #1

Hard coding a path that only exists on your development machine


MyPath = "C:\Foo\Bar";

Let's faced it. This is just lazy. It doesn't matter if you are the only one working on the project. You will eventually move to another machine or someone else will be added to the project. Next thing you know you're pulling your hair out trying to figure out why it works on one machine but not the other. By hard coding the path you've created a dependency on the exact folder structure of your hard drive.


What's worse is that you're not only forcing this on yourself or another developer but possibly the end-user as well. Save everybody some frustration and use paths relative to the main executable or if warranted, make the path configurable by the end user.