Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to work with 0-based strings in a backwards compatible way since Delphi XE5?

I'm trying to convert my current Delphi 7 Win32 code to Delphi XE5 Android with minimal changes, so that my project can be cross-compiled to Win32 from a range of Delphi versions and Android from XE5.

Starting from XE5 there are breaking changes in language aimed at future. One of such changes is zero-based strings.

In older versions with 1-based strings the following code was correct:

function StripColor(aText: string): string;
begin
  for I := 1 to Length(aText) do

but now this is obviously not right. Suggested solution is to use:

for I := Low(aText) to High(aText) do

This way XE5 Win32 handles 1-based strings and XE5 Android handles 0-based strings right. However there's a problem - previous Delphi versions (e.g. XE2) output an error on such code:

E2198 Low cannot be applied to a long string
E2198 High cannot be applied to a long string

I have quite a lot of string manipulation code. My question is - how to modify and keep above code to be compileable in Delphi 7 Win32 and Delphi XE5 Android?

P.S. I know I can still disable ZEROBASEDSTRINGS define in XE5, but that is undesired solution since in XE6 this define will probably be gone and all strings will be forced to be 0-based.

like image 203
Kromster Avatar asked Oct 21 '13 06:10

Kromster


1 Answers

If you want to support versions that use one based strings then don't define ZEROBASEDSTRINGS. That's the purpose of that conditional.

There's no indication that I am aware of that the conditional will be removed any time soon. It was introduced in XE3 and has survived two subsequent releases. If Embarcadero remove it, none of their Win32 customers will not upgrade and they will go bust. Embarcadero have a track record of maintaining compatibility. You can still use TP objects and short strings. Expect this conditional to live as long as the desktop compiler does.

In fact, all the evidence points towards the mobile compilers retaining support for one based string indexing. All the utility string functions like Pos use one based indices, and will continue to do so. If Embarcadero really are going to remove support for one based string indexing, they'll be removing Pos too. I don't believe that is likely any time soon.

Taking your question at face value though it is trivial to write functions that return the low and high indices of a string. You just use an IFDEF on the compiler version.

function StrLow(const S: string): Integer; inline;
begin
  Result := {$IFDEF XE3UP}low(S){$ELSE}1{$ENDIF}
end;

function StrHigh(const S: string): Integer; inline;
begin
  Result := {$IFDEF XE3UP}high(S){$ELSE}Length(S){$ENDIF}
end;

Update

As Remy points out, the above code is no good. That's because ZEROBASEDSTRINGS is local and what counts is its state at the place where such functions would be used. In fact it's just not possible to implement these functions in a meaningful way.

So, I believe that for code that needs to be compiled using legacy compilers, as well as the mobile compilers, you have little choice but to disable. ZEROBASEDSTRINGS.

like image 155
David Heffernan Avatar answered Oct 30 '22 23:10

David Heffernan