Synopse Open Source - Tag - TStringHelpermORMot MVC / SOA / ORM and friends2024-02-02T17:08:25+00:00urn:md5:cc547126eb580a9adbec2349d7c65274DotclearI do not like people shoot in my foot, do you?urn:md5:75d4d2226543f64f935bf141ddc119202015-05-08T10:10:00+02:002015-05-08T11:11:48+02:00AB4327-GANDIPascal ProgrammingblogDelphigenericsGoodPracticenativeNextGenperformancestringTStringHelper<p>There was some discussion about the new
<code>TStringHelper</code> feature introduced in latest versions of
Delphi.<br />
I <a href="https://plus.google.com/115779584326078289546/posts/RhkWsDP7Q6K">was
told to be some kind of archaic guy</a>, not able to see the benefit of
this.<br />
Reducing opinions to a conservative/progressive approach - another famous 10
kinds of coders - is very reductive.</p>
<p>Of course, this was IMHO unfair and my point was that I have the feeling
that some decisions about the Delphi language and RTL are inadequate.<br />
Some changes are welcome. I enjoy the introduction of generics - even if it is
was painful, and even buggy (<a href="http://stackoverflow.com/q/29906723/458259">do not use TList<T> with
managed record types in XE8</a>!).<br />
But some upcoming changes about the <code>string</code> policy - breaking
everything just because we want to align with mainstream C# or Java habits -
are just non sense to me.<br />
I really think that Embarcadero deciders like to shoot their own foot.<br />
Or - certainly worse - our own feet!</p>
<p><img src="http://www.fitnessmash.com/wp-content/uploads/2014/02/shoot-yourself-foot-internet-marketing-sabotage-online-marketing-success-training.jpg" alt="" /></p>
<p>I will post here some part of the discussion...<br />
So that we may be able to share our ideas.</p> <h3>Round 1</h3>
<p><em>First <a href="https://plus.google.com/115779584326078289546/posts/RhkWsDP7Q6K">original
question</a>.</em></p>
<blockquote>
<p>I'm starting to code using TStringHelper. What do i have to do to be able to
evaluate the expressions in the debugger?</p>
</blockquote>
<p>Short answer: this is a bug in the IDE debugger, which is not in synch with
the compiler.</p>
<p><em>Then I reacted:</em></p>
<blockquote>
<p>Sounds like if eventually I've something in common with the Delphi debugger.
I'm afraid I feel "syntax diabetic" - since I start becoming intolerant to
"syntax sugar"...</p>
<p>Either you make consistent choices, like with Oxygene, and you define a true
object oriented pascal-flavored language, or you should just leave the compiler
alone. String or record helpers, as currently implemented, are half-backed
workarounds. Even the Delphi RTL is not using them. So I'm not surprised the
Delphi debugger is not supporting those.</p>
<p>Thanks to all those helpers inflation, next major "feature" of the compiler
would probably be to deprecate plain functions calls. Then replace the
begin..end with braces, and we would start having a sub-version of C# or Java
(close to what they did offer 10 years ago), and some may be happy with it. I
for sure won't, and would always prefer C# or Java in this respect.</p>
</blockquote>
<p><em>David made a welcome precision:</em></p>
<blockquote>
<p>New code in the RTL is using string helper. Extension methods are a useful
and valuable feature. That the IDE is too lame to understand them fully is an
issue with the IDE. Same for anon methods. The way forward is to fix the IDE.
</p>
</blockquote>
<p><em>Then Stefan shared his opinion :</em></p>
<blockquote>
<p>If you buy an electric screwdriver and it does not work you can either say
"bah, electric screwdrivers are crap, I assemble my new IKEA shelf unit without
one" or you go back to the store, complain and exchange it for a working one.
Unfortunately many Delphi developers including you are doing the first.</p>
</blockquote>
<p><em>Then I had to answer:</em></p>
<blockquote>
<p>You missed my point. What I said is that if I need an electric screwdriver,
I will use Java or C#.<br />
If I follow your comparison, some of the Delphi modifications would be to
suppress half of the handle (RawByteString suppression), add a double handle
(string helpers), change the shaft into a Torx (ARC), make your screwdriver
break if you want to use it on some kind of screws (e.g. the XE8
TList<..> regression), force me to change the hand I'm using (0-based
strings). IMHO datastructures, patterns (e.g. SOLID) and algorithms have much
more importance than code expressiveness, or familiarity with mainstream
"standards".<br />
Using aString.IndexOf(aChar) or pos(aChar,aString) don't change my mind.<br />
BTW, I find your comment offensive. I use C# as a Senior Dev and Architect,
including all its latest features. I'm perhaps less sensitive to hype than
other people. When I saw <a href="https://www.youtube.com/watch?v=GDVAHA0oyJU">Barbara's Liskov presentation
video</a> - I just felt at home.Her POV about Java or C# is refreshing. Her
students code in C or C++, even when they do experimentation about new
languages - just because they know what they do. Or when I learned to code in
Clojure, it opened new perspectives to me, and made my Delphi code somewhat
better. Far away from syntax sugar.</p>
</blockquote>
<p><img src="http://funny-pics.co/wp-content/uploads/funny-cat-with-screwdriver.jpg" alt="" /></p>
<h3>Round 2</h3>
<p><em>Second related <a href="https://plus.google.com/115779584326078289546/posts/RhkWsDP7Q6K">question</a>.</em></p>
<blockquote>
<p>What am i missing here? This is how TStringHelper.Remove looks:</p>
<pre>
<code>function TStringHelper.Remove(StartIndex, Count: Integer): string;
begin
Result := Self;
System.Delete(Result, StartIndex + 1, Count);
end;</code>
</pre>
<p>The Result := Self will copy the string. Do you think this was
intentional?</p>
</blockquote>
<p><em>Olivier explained:</em></p>
<blockquote>
<p>The function returns a string. Also, the input string (self) could be a
const. And, all Stringhelper functions are emulating 0-based strings in
preparation to the future.</p>
</blockquote>
<p><em>Then I reacted (of course, I have nothing against Oliver: I just wanted
to react to those language changes):</em></p>
<blockquote>
<p>We are so lucky to have a so bright future. This is a feature I desperately
expected and pray for every night before going to bed. Next step would be to
make all strings immutable (just because Java or C# do), and break all the COW
benefits. All this is non-sense...</p>
</blockquote>
<p><em>But what I would like to discuss is the following:</em></p>
<blockquote>
<p>BTW, the fact that TStringHelper treat self as immutable is another
testimony of the potential "string immutability" we were talking to.<br />
As a result, this TStringHelper.Remove pseudo-method would be much less
efficient than the system.Delete() function, since both strings would remain in
memory, so there would be a new memory allocation, whereas delete() is able to
change the original string content in place (if its refcount=1, which is very
likely).<br />
If the string is several MB long, the system.Delete() would be very fast (just
a move in-place of the right part of the string, with FastMM4 doing in-place
reallocation), whereas TStringHelper.Remove() would use twice more memory, and
would always move the whole string content.<br />
When I read in the official EMB documentation that "older System unit
string-handling functions are deprecated and support might be removed in the
future", I really think: are those people crazy enough to shot themself in the
foot?</p>
</blockquote>
<h3>Round 3</h3>
<p>OK. Let's go to the ultimate point.<br />
<code>TStringHelper</code> is just broken, even at compiler level.<br />
Its methods do NOT work for sub types.</p>
<p>The following would not compile:</p>
<pre>
type<br /> mystring = type string;<br />var s: string;<br /> s2: mystring;<br />begin<br /> s := '1234';<br /> writeln(s.IndexOf('3'),'=2');<br /> s2 := '1234';<br /> writeln(s2.IndexOf('3'),'=2');
</pre>
<p>It complains on the last line compilation (I tested with XE6), with a:</p>
<pre>
[dcc32 Error] stringhelper.dpr(20): E2018 Record, object or class type required
</pre>
<p>IMHO this is just a show stopper.<br />
If you define your own sub-type, you would not be able to use the string helper
syntax.<br />
Then you would have to use the system.pas classic functions - which will work,
of course.</p>
<p>I use a lot of those custom types, which are IMHO mandatory to write safe
code.<br />
Strong typing, even for simple types, is a very good practice.<br />
If you define</p>
<pre>
type<br /> TTimeInSeconds = type double;<br /> TTimeInMilliseconds = type double;
</pre>
<p>Then the compiler will make a difference between a second and millisecond
variable, your function definitions would be much more efficient.<br />
This is one of the reasons why the NASA would never use JavaScript to write its
software. It may <a href="http://www.computerworld.com/article/2515483/enterprise-applications/epic-failures--11-infamous-software-bugs.html">
lead into disasters</a>...</p>
<p>So, we are told by Delphi documentation to use TStringHelper
methods...<br />
And we can not use it on custom sub types?<br />
I hope you start understanding my point.</p>
<h3>Let's discuss</h3>
<p>For a refreshment about TStringHelper, <a href="https://theroadtodelphi.wordpress.com/2012/09/05/exploring-delphi-xe3-record-helpers-for-simple-types-system-sysutils-tstringhelper/">
check this blog article</a>.</p>
<p>If we look at the whole note in the <a href="http://docwiki.embarcadero.com/Libraries/XE8/en/System.SysUtils.TStringHelper%EF%BB%BF">
official TStringHelper documentation</a>, you would find this:</p>
<blockquote>
<p>Note: You are encouraged to move to the TSringHelper methods when
manipulating strings on all platforms. To preserve backward compatibility with
existing code as much as possible, the longstanding functions in the System
unit that deal with string indices will continue to function with 1-based
strings, and also perform the necessary automatic conversions to do the correct
operations on 0-based strings as well. One example is System.Pos. However,
these older System unit string-handling functions are deprecated and support
might be removed in the future.</p>
</blockquote>
<p>Take some time to listen to Barbara's conference (<a href="https://www.youtube.com/watch?v=GDVAHA0oyJU">link above</a>).<br />
You will find out why I had to react.<br />
We are too much polluted with the "mainstream way of doing things".<br />
Strings being zero-indexed or one-indexed, or having functions or methods...
sincerely no life changer to me. I switch from C# to Delphi strings without a
problem, every day. If I would not be able to, I would not be able to do any
coding, I suspect. On the contrary, I guess it will help fighting against
Alzheimer kind of disease...</p>
<p>If those moves at language and RTL level were only optional, I would not
mind. But we are forced to follow those decisions which I personally find
aberrant.<br />
The main aberrations being that it breaks existing code, and induce performance
penalties in regard to amazing patterns like <a href="http://en.wikipedia.org/wiki/Copy-on-write">COW</a>, which made Delphi
distinctive and appealing to me.<br />
If I have to rewrite the code, just to let it be more Javaish or C#ish, I would
rewrite it in Java or C#.<br />
And do not argue that "immutable strings are multi-thread friendly", which is a
bad joke when you look at the <a href="https://blog.synopse.info?post/post/2013/05/21/Performance-issue-in-NextGen-ARC-model">current RTL
implementation of latest features</a>... far away from multi-thread friendly.
Delphi COW strings were never a bottleneck - you would even be able to change
the memory manager, if needed. The TStringBuilder approach is a need for
immutable strings, and is a <a href="https://www.delphitools.info/2013/10/30/efficient-string-building-in-delphi/3/">
performance nightmare</a> - I can tell you that... Even in .Net they did
tremendous attempts to tune the performance of this C#
StringBuilder... </p>
<p>The more I think about it, the more I like FPC pragmatic approach, about
language evolution, and diverse compile-time flavors, known as <a href="http://www.freepascal.org/docs-html/prog/progsu105.html">modes</a> -
which could be quite powerful, since e.g. it allows to <a href="http://wiki.freepascal.org/FPC_PasCocoa">compile native iOS/MacOS objects</a>
without the need to use runtime level interfaces, as the Delphi compiler
does.<br />
When FPC introduced <a href="http://lists.freepascal.org/fpc-announce/2013-February/000587.html">helpers
for primitive types</a>, they offered a tunable approach via modes, and did not
deprecate the <em>system.pp</em> string functions!</p>
<p>Feedback is <a href="http://synopse.info/forum/viewtopic.php?id=2556">welcome in our forum</a>, or
in <a href="https://plus.google.com/u/0/communities/103113685381486591754">the
Google+ forums</a>.</p>