Delphi Handbooks Collection


Delphi XE Handbook


Delphi 2010 Handbook


April 16, 2008

Static Internal DSL in Delphi

After an introductory blog post, here is my code example of a static internal Domain Specific Language written in Delphi.

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...





 

10 Comments

Static Internal DSL in Delphi 

Not sure why recently the DSL "thingy" is being
confused with the "return this" (self in Delphi case)
style of programming.
IMHO they are different things, each one with its pros
and cons, but definitely separated issues.

DSL make a lot of sense when you need to change often
business logic or you want make it customizable by users.

The "return this" AFAIK is a Ruby idiom, it's quite
nice for simple things, but it could became cumbersome
when you need to define a not so trivial rule.

my 2 euro cents
Comment by uberto [http://uberto.wordpress.com] on April 16, 18:32

Static Internal DSL in Delphi 

@Uberto: , the "return this" idiom is much much older
than the Ruby language and at least the Delphi pascal
KOL library predates ruby several years.
Also, I would like to point out that what Marco is
trying to explain is that to be able to even write DSL
you need this concept. In the background you need it,
but you can refine it for the end user to be more
elegant (like defining syntax). I think this series is
a gallant and eloquent effort on a subject that is
obviously not too obvious for most :-)
Comment by Thaddy [http://thaddy.com] on April 16, 21:33

DSL links 

Hi Marco,

Even DSL will be somehow exotic for Delphi, I think 
that is an area that might be investigated ... 

Bellow there are some links/articles that might 
provide you some additional ideas how the DSL can be 
used/improved:

A Domain-Specific Language for unit manipulations
http://groovy.dzone.com/news/domain-specific-language-
unit-

The 'Language' in Domain-Specific Language Doesn't 
Mean English (or French, or Japanese, or ...)
http://pragdave.blogs.pragprog.com/pragdave/2008/03/
the-language-in.html

Jay Fields and Zak Tamsen on Domain Specific Languages
http://www.infoq.com/interviews/jay-fields-zak-tamsen-
on-dsls

Using Groovy's FactoryBuilderSupport to Build 
Internal DSL
http://vladimirvivien.com/blogs/ot/2008/03/using-
groovys-factorybuildersupport-to.html

Groovy DSL steps
http://www.warneronstine.com/blog/articles/2007/06/05/
groovy-dsl-steps

GroovyLab: Provides a domain specific language (DSL) 
for math engineering (matlab-like syntax)
http://groovy.codehaus.org/GroovyLab

Guillaume Laforge on Groovy and DSLs
http://www.infoq.com/interviews/guillaume-laforge-
groovy

An Approach to Internal Domain-Specific Languages in 
Java
http://www.infoq.com/articles/internal-dsls-java
Comment by El Cyparu on April 17, 00:07

Static Internal DSL in Delphi 

"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"


Did you really think that was viable when you wrote it?


If you need non-programmers to write business rules,
you provide them with a rule engine/rules environment
within your application - the last thing you want to
do is compile their rules into the app itself.

There's no need to bend/twist Delphi (what?  you're
going to give them Delphi so they can write their
rules in a non-Delphi-like way?).

Much easier to put a scripting engine in your app and
let them use a familiar language to write their rules
where they can test - and run - their rules safely
under the watchful eye of a guardian/sandbox in the
app itself.

Ironically, they are likely to be far more familiar
with VBScript or JavaScript than they are with any
"DSL" that you might provide (after all, it's still
the developers particular implementation of a language
that they think "fits" their users domain - if they
understood that domain well enough the user wouldn't
be complaining about how hard it is to write the rules
in the first place, and if you don't understand the
domain sufficiently well to write a rules engine that
the user finds usable, you have very little chance of
being any more successful in providing an entire DSL
that will be any better).



Sorry, but this still reeks of "Magic Bullet Wonder
Solution That Will Be Great Fun To Write And Won't It
Be Impressive When It's Done" - but not solving an
actual problem.

The problems it solves are - as far as I can see -
already solved very satisfactorily.

(Also just to add a "concur" to other posts - this
latest post seems to be muddying the waters and mixing
wholly different an unrelated techniques to the
previous discussions about dynamic invocation)

+0.02
Comment by Jolyon Smith [http://www.deltics.co.nz] on April 17, 00:34

Static Internal DSL in Delphi 

A few replies are due...

Uberto, the return self style is often used for DSL
implementations, particularly in Java. They are
different things, of course, but are often combined.

El, thanks for the links.

Joylon, I stand with what I wrote. Why would
non-programmers use JavaScript rather than a subset of
Delphi, I don't know. An external language for
business rules makes sense (I wrote this is one of 3
options), but an internal one can be a tad more
efficient (and require less developer work). Also, a
DSL is an extremely limited language (or subset), you
don't want to have one allowing loops and other
complex constructs. For your information, DSL are used
(in other languages) to solve real business problems
and in very large projects. Rails can be seen as a
DSL, and it is getting popular. And I'm not muddying
waters and covering something else, dynamic methods
invocation is another techniques for implementing an
internal DSL. I'll post more, you'll complain more...
Comment by Marco Cantù [http://www.marcocantu.com] on April 17, 01:08

Static Internal DSL in Delphi 

"Why would non-programmers use JavaScript rather than
a subset of Delphi, I don't know"

They probably wouldn't, but non-programmers do use
VBA/VB Script everyday, which I imagine is why so many
applications provide a VBA/VB Script environment
specifically for users - non-programmers in many cases
- to add new rules and behaviours.

I only mentioned JavaScript for completeness, in case
someone might choose to focus on the shortcomings of
VBA/VB Script.


The "Domain Specific" language that such users have to
learn is then simply the object model of the
particular application which - by necessity - reflects
THAT application implementation specifically.



"you don't want to have one allowing loops and other
complex constructs"

Don't I?  Why not?  More specifically, why don't the
users?  Who's to say what the broad generality of
users do and do not want from any approach that offer
to provide a way to implement DSL's in any number of
possible solutions?

My suspicion is that this "want" is actually driven by
a failing in the approach.  "I say you want This, but
this doesn't give you That, therefore you don't [read:
cannot be allowed to] want That, and if you don't want
That why would you use something that gives you both
This AND That.  You get This without That, so you get
what [I say that it is that] you want."

;)


"I'll post more, you'll complain more..."

"Complain"?  The only "complaint" is that you haven't
ever actually answered some very simple questions:

Why is it useful?
Why is it better than XYZ alternative?

These "Why" questionare the useful questions because
once these are answered, there actually becomes a
point in pursuing the "What" and the "How" of actually
doing it.

I can't - and wouldn't - complain about anything
else... you can spend your time doing and blogging
about whatever you like, but if you have an insight
into some practical uses for this stuff I would have
thought you would be eager to share those insights so
that others could get the manifold benefits that you
see available to them.

I keep reading these posts in the hope that one day
you will shed some light on the real benefits,
precisely because the idea's themselves are
interesting and I'd LOVE to be able to justify using them.

If it's just something you find interesting and are
pursuing out of intellectual curiosity, then
fantastic.  Knock yourself out.  But at least say so,
so that I can quit wasting time reading the posts in
hope of gaining some practical insight.

Of course, I'll probably still read them in my
"downtime", to satisfy my __own__ intellectual curiosity.

:D
Comment by Jolyon Smith [http://www.deltics.co.nz] on April 17, 05:46

Static Internal DSL in Delphi 

Excellent article Marco.  The biggest benefit of DSLs 
is the huge improvement to readability that they 
provide.  And the leap is so large the benefits 
extend to writing "code" as well.  

I almost completely disagree with everything Jolyon 
says (those brothers of ours across the Tasman are a 
strange lot :)  Must be all those sheep :)  

I don't think Delphi is being bent or twisted in any 
unnatural way -- anything that adds to the ease of 
reading, writing and maintaining code has to be 
good.  And what better way of getting the business 
logic right than to have the business experts write 
it (well, at least be able to read and check it)!  I 
have worked in countless places where the programmers 
have little to no idea of or interest in the business 
rules -- many are nuts and bolts people who don't 
give a toss about what the project is really trying 
to deliver to customers.

"Much easier to put a scripting engine in" -- I very 
much doubt it.  I embedded python into a Delphi app - 
there was a huge amount of plumbing to get this 
going.  Providing "a rules engine/environment within 
your app" is quite possibly a larger task.  DSLs, as 
Marco is demonstrating, are here now and don't 
require anything like the work.  You can start small 
and build the DSL as you need/go.

DSLs are not the solution to all problems but they 
are going to be an increasingly useful tool in the 
future; especially as we move to more dynamic 
languages. Even Microsoft have seen the light - look 
at what they are doing with C#, IronPython, the DLR 
(not the CLR).

Richard

Comment by Richard King [] on April 17, 08:06

Static Internal DSL in Delphi 

 @Marco: "They are different things, of course, but
are often combined." 
sure, but I'm still unsure why. Programmers should
know better than this...

 @Joylon: "If you need non-programmers to write
business rules,
you provide them with a rule engine/rules environment
within your application - the last thing you want to
do is compile their rules into the app itself."

maybe I haven't been very clear, sorry. I agree that
you should load dynamically the DSL.

That's exactly why I find the "return this" idiom not
very suited for DSL, because DSL compiled inside the
app are not very useful.

I know that Ruby didn't invented it but it's the first
mainstream language AFAIK that makes it default.

The whole point of DSL is to make non-programmer (not
morons, skilled engineers that know their domain)
describe easily their domain with specific syntax.
Comment by uberto [http://uberto.wordpress.com] on April 17, 13:40

Static Internal DSL in Delphi 

 I can think of several places for a dsl inside the
application.  I am considering adding dsl features to
tiopf (www.tiopf.com) for make filtering data easier.

There are several reasons for using a dsl.  Allowing
non programers to make changes is only one, and is of
no interest to me.  
Other reasons might be:
Allowing a consistent interface regardless of the
background implementation (ie not worrying about
whether  you are querying a database, filtering an in
memory dataset or parsing an xml stream.
Allowing a programmer to use difficult functionality
that they are not familiar with (ie a simplifying dsl
for regular expressions.

Linq is a good example of what a dsl can do.  I would
love to be able to that inside delphi code.
Comment by Sean [http://www.sourceitsoftware.com] on April 18, 05:13

Static Internal DSL in Delphi 

 "so that I can quit wasting time reading the posts"

We'd be much happier if you not only did not read the
posts but didn't comment on them either, Jollyon.  You
just don't get many things do you?

The biggest benefit of DSLs is not for non-programmers
to write the business logic but for both the
programmers and business people to be able to read and
communicate using a common language that is more
easily understood than raw source code.
Comment by Richard K on April 4, 03:21


Post Your Comment

Click here for posting your feedback to this blog.

There are currently 0 pending (unapproved) messages.