April 3, 2009
A recent post by Primoz Gabrijelcic about Fluent XML has turned on interest for fluent interfaces in Delphi.
A recent post by Primoz Gabrijelcic about Fluent XML has turned on interest for fluent interfaces in Delphi. What is a fluent interface or fluent programming styles? It has many sides, but one of the ideas is to let methods return the object they are applied to, so that the next method call can be chained to th first one. The only example in Delphi's native libraries is in the TStringBuilder class. With this class you can write (using a traditional approach):
sBuilder1.Append('one');
sBuilder1.Append('two');
Using the fluent interface you can write (instead):
sBuilder1.Append('one').Append('two');
Of course you might still want to have the two Append calls on two separate lines, but without having to repeat the name of the objects they are applied to. I had a long discussion (with other demos) on this topic in my post "Static Internal Dsl in Delphi", back in April 2008.
But if you want to see a really nice implementation of the idea, you can follow the link to the Fluent XML article, which applies the same principle to a situation in which alternative appraoches are not as nice. I like Primoz appraoch of combining subnodes and attributes in an XML building class, I liek it really very much. The only element I don't like is the use of navigational methods within the class. I'd rather be able to have an AddChildren method to which you can pass multiple nodes, but being in a class all day today (and tomorrow) and spedning the evening at the Delphi 2009 Productivity event in Chicago (which is going on while I'm typing this) I had no time for experiments. Primoz has made the full code available in a second post, and I'll download his code ASAP and see what I can come up with. But kudos to him for his nice fluent interface and a nice appraoch for working with XML (something I happen to use a lot).
Time to get back to hear Anders, now...
posted by
marcocantu @ 4:51AM | 4 Comments
[0 Pending]
Fluent Interfaces in Delphi
Or alternatively you could write:
with sBuilder1 do
begin
Append('one');
Append('two');
end;
;)
Which has the added advantage of not building up a
huge call hierarchy to be unravelled if something goes
wrong in one of your calls, and the debugger dumping
you back on a single statement spanning (potentially)
dozens of lines of code with no indication of which
/part/ of that line is directly responsible.
I don't understand why this technique gets a "warm
fuzzy" name ("Fluent") when "With" receives so much
disdain.
They achieve the same thing.
(With isn't without it's problems - no argument on
that score, but this so called "Fluent" API is also
far from perfect, imho)
It's another one of those things that I can understand
why it appeals to the lazy part of all of us, but I
wouldn't want to live with code written that way for
any length of time.
A little extra time spent creating code is
insignificant (in the kinds of apps I work on)
compared to the length of time that the code will
spend (and have spent on it) in maintenance.
For disposable code (quick, use-and-forget utilities
etc), the equation balances out differently of course.
Comment by Jolyon Smith on April 3, 06:58
Fluent Interfaces in Delphi
Just a word of caution here: fluent style can improve
readability, but it's not for everyone in every
situation because of one key disadvantage: you can't
breakpoint and evaluate in the middle of a fluent
expression... that is, unless you're familiar with the
CPU view and ASM.
So it's truly a great tool only *if* your familiarity
with the debugger extends to the CPU view.
Comment by Eric
[http://delphitools.info/]
on April 3, 09:20
Fluent Interfaces in Delphi
jQuery anyone?
Comment by Julian
[http://www.setup32.com]
on April 3, 16:52
Fluent Interfaces in Delphi
Although not exactly the same, Borland provided this
approach already in the 90s in its Turbo Vision
library. Remeber how were menus or the status bar
created in those times?
StatusLine := New(PStatusLine, Init(R,
NewStatusDef(0, $FFFF,
NewStatusKey('~F10~ Expose', kbF10, cmExpInteg,
NewStatusKey('~F9~ Monitor', kbF9, cmExpMon,
NewStatusKey('~ShiftF9~ Grab', kbShiftF9,cmExpGrab,
NewStatusKey('~F3~ Open', kbF3, cmFOpen,
NewStatusKey('~F2~ Save', kbF2, cmFSave,
NewStatusKey('~AltX~ Exit', kbAltX, cmQuit,
NewStatusKey('~ShiftF10~ Display', kbShiftF10,
cmDisplay, nil))))))), nil)));
PD taken from:
http://www.ddj.com/architect/184408571?pgno=5
Comment by Albert Almeida on April 3, 17:07
There are currently 0 pending (unapproved) messages.