After an introductory blog post, here is my code example of a static internal Domain Specific Language written in Delphi. Let's clarify the terms first. An internal DSL is a Domain Specific Language written in the host language. A static DSL is one written in a static language, as it is often the case of Java, C#, and similar compiled languages. This is also the case of Delphi, if you don't take into account its dynamic method resolution capabilities.

Again, code like in this demo could replace an external configuration file or a different way of coding the same, making the code more understandable to non-hardcore programmers and more English-language like. Consider as an example of the code you might be generally using (and I use a lot as well):

  Appt := TStdAppointment.Create;
Appt.At := 'New York';
Appt.FromDate := EncodeDateTime
(2007, 12, 12, 9, 0, 0, 0);
Appt.ToDate := StrToDate ('12/12/2007') +
StrToTime ('12:00pm');
Appt.Description := 'Delphi Dev. Meeting';
ShowMessage (Appt.ToString);

From Properties to Functions

This is a classic property-based way of writing code. Nice as it looks to developers, function based code at times is more readable (again, we are thinking non programmers here), so we could write instead:

Appt.At ('New York');
Appt.Description ('Delphi Dev. Meeting');

Even more, we can hide the explicit constructor, using a helper function (that does call the constructor), like in:

app := Appointement('Web Conference')

This replaces the constructor call and an assignment in one single more readable line. Yes, this code looks more English-oriented in Ruby, a language in whcih you can omit the parenthesis around parameters, but it is not too bad even in Delphi (of Java, or C#... you name it).

Methods chaining

The other technique that makes a difference in readability is methods chaining. You can turn the At and Description assignment procedures into functions that return the object they are applied to, coding them like this:

function TAppointment.at (aLocation: string): TAppointment;
begin
fLocation := aLocation;
Result := self;
end;

This coding style allows you to avoid repeating the object variable over and over, on multiple lines of code, going for something more intuitive like:

  app.from(Tomorrow).at('Milan');    

Now combining this with the constructor helper function you can end up with the following code, which replaces the original property-oriented version:

  app := Appointement('Web Conference').
from (Tomorrow).
upto (DayAfter(Tomorrow)).
at('Milan');

This code uses also a couple of helper functions, like Tomorrow that is part of DateUtils and DayAfter that I added myself. Again, much better in readability terms than writing Now + 1.

Conclusion

Before you start posting complaints, consider that I don't think this is a good generic way of writing Delphi code, it makes sense only when you need a DSL-oriented approach, like when you want to let non-programmers write business oriented rules that you'll compile into your Delphi application. Second, using a static internal DSL is at times a good option, but there are also dynamic internal DSL and external DSL, so this it not "the solution" but only one of many options.

At times I feel the Delphi community tends to be more static than other communities in terms of coding style, but the truth is probably that people who experiment in Delphi are not as much in the forefront as it happens elsewhere...