The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 2,229 other followers

Delphi: rolling your own code or (dis)trusting the libraries that ship with Delphi?

Posted by jpluimers on 2015/09/09

Over the two decades I’ve come across a lot of Delphi projects.

All of them have one thing in common: even for functionality available in the Delphi libraries, much of that code was self-written.

You even see this in big libraries that have shipped with Delphi bit not originate from the Delphi team. Take Indy: lots of “roll your own” in it.

I’ve made some thoughts about that, and see these main causes with the points below.

What’s your thought on this?

  • Naming in the Delphi libraries is very confusing; there seem to be no (enforced or publicly available) naming guidelines within the Delphi R&D team (even though Charlie Calvert published one a long time ago), which makes it harder with the growth of the team:
  • Functionality in the Delphi libraries is either doubled, or only half done. For instance,
    • there is a StartsWith, but no EndsWith,
    • the implementations of StartsStr and EndsStr are not symmetric (see unit tests below) nor the documentation points to each other, their parameter order is the opposite of what you expect and use abbreviations.
  • Functionality has been broken or limited in use for a very long time. For instance,
  • Documentation on expected functionality is limited. There is the Delphi Unit Test project to show and set expectations, but that seems to have silently become dormant on BitBucket.
  • Lots of library functionality has taken more than one Delphi version to become stable or (even longer, if at all): mature. Companies don’t have enough time to wait for that, and roll the things they do need on their own.
    • ClientDataSets, DBX, SOAP, JSON and FMX are key examples of this. They have taken a long long time to mature. Even worse: some of these are now even deprecated or replaced.

A quick example on the issues with StartsWith, StartsStr and EndsStr:

It helps a lot when you write your own unit tests to set (and verify) expectations on even simple RTL functionality.

But writing these is time consuming, and should be the responsibility of the library vendor.

unit StringUtils;
function EndsWith(const Value: string; const SubString: string): Boolean;
function StartsWith(const Value: string; const SubString: string): Boolean;
function EndsWith(const Value: string; const SubString: string): Boolean;
// EndsStr is not symmetric to StartsStr and fails to handle empty SubString.
if SubString = '' then
Result := True
Result := EndsStr(SubString, Value);
function StartsWith(const Value: string; const SubString: string): Boolean;
Result := StartsStr(SubString, Value);

view raw
hosted with ❤ by GitHub

unit StringUtilsTests;
// Delphi is very confusing in naming, when (not) using abbreviations and parameter order.
// So add an EndsWith that complements HTTPUtil.StartsWith (which could have used StartsStr in the first place:
// the RTL developers are Embarcadero don't even know what is inside the RTL!)
// Furthermore, in the RTL, StartsStr and EndsStr are not symmetric.
TStringFunctionTests = class(TTestCase)
procedure EndsStrTests;
procedure EndsWithTests;
procedure StartsStrTests;
procedure StartsWithTests;
procedure StartsWithHTTPUtilTests;
function CreateMessage(const FunctionName, Value, SubString: string): string;
LLeft = 'foo';
LRight = 'bar';
LValue = LLeft + LRight;
function TStringFunctionTests.CreateMessage(const FunctionName, Value, SubString: string): string;
Result := Format('%s("%s", "%s")', [FunctionName, Value, SubString]);
procedure TStringFunctionTests.EndsStrTests;
CheckTrue(EndsStr(LRight, LValue), CreateMessage('EndsStr', LRight, LValue));
CheckFalse(EndsStr(LLeft, LValue), CreateMessage('not EndsStr', LLeft, LValue));
// Unlike StartsStr, EndsStr does not match on an empty string.
// This can never be fixed as EndsStr has been 'in the wild'.
// CheckTrue(EndsStr('', LValue), CreateMessage('EndsStr', '', LValue));
procedure TStringFunctionTests.EndsWithTests;
CheckTrue(EndsWith(LValue, LRight), CreateMessage('EndsWith', LValue, LRight));
CheckFalse(EndsWith(LValue, LLeft), CreateMessage('not EndsWith', LValue, LLeft));
CheckTrue(EndsWith(LValue, ''), CreateMessage('EndsWith', LValue, ''));
procedure TStringFunctionTests.StartsStrTests;
CheckFalse(StartsStr(LRight, LValue), CreateMessage('not StartsStr', LRight, LValue));
CheckTrue(StartsStr(LLeft, LValue), CreateMessage('StartsStr', LLeft, LValue));
CheckTrue(StartsStr('', LValue), CreateMessage('StartsStr', '', LValue));
procedure TStringFunctionTests.StartsWithTests;
CheckFalse(StartsWith(LValue, LRight), CreateMessage('not StartsWith', LValue, LRight));
CheckTrue(StartsWith(LValue, LLeft), CreateMessage('StartsWith', LValue, LLeft));
CheckTrue(StartsWith(LValue, ''), CreateMessage('StartsWith', LValue, ''));
procedure TStringFunctionTests.StartsWithHTTPUtilTests;
CheckFalse(HTTPUtil.StartsWith(LValue, LRight), CreateMessage('not HTTPUtil.StartsWith', LValue, LRight));
CheckTrue(HTTPUtil.StartsWith(LValue, LLeft), CreateMessage('HTTPUtil.StartsWith', LValue, LLeft));
CheckTrue(HTTPUtil.StartsWith(LValue, ''), CreateMessage('HTTPUtil.StartsWith', LValue, ''));

view raw
hosted with ❤ by GitHub


  • I stopped reporting issues like these in QC (quality central) more than a year (the web interface is a dork, and the SOAP API is has a huge security issue: it is http-only, passing EDN credentials – giving access to all your Embarcadero information – over the line in plain text, and there have been no signs of improvement since I reported the security risks in April 2014).
  • I won’t publish bugs in JIRA quality as long as it is not publicly indexed by Google (like QC is/was).
  • Many other languages and libraries have good naming guidelines available.
  • Except for the naming conventions (which are dreadful!) I’ve limited the examples as they are all over the RTL, VCL and FMX frameworks in all Delphi versions. Hence the examples from the Delphi 2007 documentation: more modern Delphi versions have improved, but not far enough, and Delphi 2007 is still in use by lots of Delphi projects.


One Response to “Delphi: rolling your own code or (dis)trusting the libraries that ship with Delphi?”

  1. Rollo said

    Yes, that is exactly what I do. Search the essence of the libraries and make my own versions to replace the original ones. Still many original libraries are cluttered in my code, but the biggest advantage fpr me is also to make the libraries working as I expect. This means also some kind of Bugfixing or Logicfixing if you will.
    A library where I can 100% trust on, and where I can reflect and flatten out changes: like Unicode, 0- 1-based stuff, etc.
    Make my life a little easier.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: