I do not like people shoot in my foot, do you?
There was some discussion about the new
TStringHelper feature introduced in latest versions of
I was told to be some kind of archaic guy, not able to see the benefit of this.
Reducing opinions to a conservative/progressive approach - another famous 10 kinds of coders - is very reductive.
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.
Some changes are welcome. I enjoy the introduction of generics - even if it is was painful, and even buggy (do not use TList<T> with managed record types in XE8!).
But some upcoming changes about the
string policy - breaking
everything just because we want to align with mainstream C# or Java habits -
are just non sense to me.
I really think that Embarcadero deciders like to shoot their own foot.
Or - certainly worse - our own feet!
I will post here some part of the discussion...
So that we may be able to share our ideas.
First original question.
I'm starting to code using TStringHelper. What do i have to do to be able to evaluate the expressions in the debugger?
Short answer: this is a bug in the IDE debugger, which is not in synch with the compiler.
Then I reacted:
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"...
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.
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.
David made a welcome precision:
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.
Then Stefan shared his opinion :
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.
Then I had to answer:
You missed my point. What I said is that if I need an electric screwdriver, I will use Java or C#.
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".
Using aString.IndexOf(aChar) or pos(aChar,aString) don't change my mind.
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 Barbara's Liskov presentation video - 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.
Second related question.
What am i missing here? This is how TStringHelper.Remove looks:
function TStringHelper.Remove(StartIndex, Count: Integer): string; begin Result := Self; System.Delete(Result, StartIndex + 1, Count); end;
The Result := Self will copy the string. Do you think this was intentional?
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.
Then I reacted (of course, I have nothing against Oliver: I just wanted to react to those language changes):
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...
But what I would like to discuss is the following:
BTW, the fact that TStringHelper treat self as immutable is another testimony of the potential "string immutability" we were talking to.
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).
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.
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?
OK. Let's go to the ultimate point.
TStringHelper is just broken, even at compiler level.
Its methods do NOT work for sub types.
The following would not compile:
mystring = type string;
var s: string;
s := '1234';
s2 := '1234';
It complains on the last line compilation (I tested with XE6), with a:
[dcc32 Error] stringhelper.dpr(20): E2018 Record, object or class type required
IMHO this is just a show stopper.
If you define your own sub-type, you would not be able to use the string helper syntax.
Then you would have to use the system.pas classic functions - which will work, of course.
I use a lot of those custom types, which are IMHO mandatory to write safe
Strong typing, even for simple types, is a very good practice.
If you define
TTimeInSeconds = type double;
TTimeInMilliseconds = type double;
Then the compiler will make a difference between a second and millisecond
variable, your function definitions would be much more efficient.
So, we are told by Delphi documentation to use TStringHelper
And we can not use it on custom sub types?
I hope you start understanding my point.
For a refreshment about TStringHelper, check this blog article.
If we look at the whole note in the official TStringHelper documentation, you would find this:
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.
Take some time to listen to Barbara's conference (link above).
You will find out why I had to react.
We are too much polluted with the "mainstream way of doing things".
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...
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
The main aberrations being that it breaks existing code, and induce performance penalties in regard to amazing patterns like COW, which made Delphi distinctive and appealing to me.
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#.
And do not argue that "immutable strings are multi-thread friendly", which is a bad joke when you look at the current RTL implementation of latest features... 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 performance nightmare - I can tell you that... Even in .Net they did tremendous attempts to tune the performance of this C# StringBuilder...
The more I think about it, the more I like FPC pragmatic approach, about
language evolution, and diverse compile-time flavors, known as modes -
which could be quite powerful, since e.g. it allows to compile native iOS/MacOS objects
without the need to use runtime level interfaces, as the Delphi compiler
When FPC introduced helpers for primitive types, they offered a tunable approach via modes, and did not deprecate the system.pp string functions!