Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2025-04

Copy() and ZeroBaseStrings

12 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bart

Hi,

Is this a known issue?
===
program z;

{$longstrings on}
{$zerobasedstrings on}
var
  S, T: string;
begin
  S := 'ABC';
  write('S[0]        = "',S[0],'"');
  if (S[0]  'A') then writeln(', FAIL: expected: A') else writeln(' [Ok]');
  write('S[1]        = "',S[1],'"');
  if (S[1]  'B') then writeln(', FAIL: expected: A') else writeln(' [Ok]');
  write('S[2]        = "',S[2],'"');
  if (S[2]  'C') then writeln(', FAIL: expected: A') else writeln(' [Ok]');
  T := Copy(S,0,1);
  write('Copy(S,0,1) = "',T,'"');
  if (T  'A') then writeln(', FAIL: expected: A') else writeln(' [Ok]');
  T := Copy(S,1,1);
  write('Copy(S,1,1) = "',T,'"');
  if (T  'B') then writeln(', FAIL: expected: B') else writeln(' [Ok]');
end.
===

Outputs:
S[0] = "A" [Ok]
S[1] = "B" [Ok]
S[2] = "C" [Ok]
Copy(S,0,1) = "A" [Ok]
Copy(S,1,1) = "A", FAIL: expected: B

(I played a little with this because Copy() accepts Index < 1 for "normal" AnsiStrings, and in Lazarus Utf8Copy() does not, so I wanted to see how his behaved with zerobasedstrings on.
B.t.w. Is there an associate short option for this, as currently you cannot check {$IFOPT zerobasedstrings+} nor any other longoptions IIRC.)

Bart

Reply by email

Sven Barth
to Bart

Bart via fpc-devel schrieb am So., 6. Apr.
2025, 23:19:

Show quoted text 43 lines
Hi, Is this a known issue? === program z; {$longstrings on} {$zerobasedstrings on} var S, T: string; begin S := 'ABC'; write('S[0] = "',S[0],'"'); if (S[0] 'A') then writeln(', FAIL: expected: A') else writeln(' [Ok]'); write('S[1] = "',S[1],'"'); if (S[1] 'B') then writeln(', FAIL: expected: A') else writeln(' [Ok]'); write('S[2] = "',S[2],'"'); if (S[2] 'C') then writeln(', FAIL: expected: A') else writeln(' [Ok]'); T := Copy(S,0,1); write('Copy(S,0,1) = "',T,'"'); if (T 'A') then writeln(', FAIL: expected: A') else writeln(' [Ok]'); T := Copy(S,1,1); write('Copy(S,1,1) = "',T,'"'); if (T 'B') then writeln(', FAIL: expected: B') else writeln(' [Ok]'); end. === Outputs: S[0] = "A" [Ok] S[1] = "B" [Ok] S[2] = "C" [Ok] Copy(S,0,1) = "A" [Ok] Copy(S,1,1) = "A", FAIL: expected: B (I played a little with this because Copy() accepts Index < 1 for "normal" AnsiStrings, and in Lazarus Utf8Copy() does not, so I wanted to see how his behaved with zerobasedstrings on.

Please report a bug.

B.t.w. Is there an associate short option for this, as currently you

cannot check {$IFOPT zerobasedstrings+} nor any other longoptions IIRC.)

No there's not.

Also it would be best to simply document as UTF8Copy working 1-based because you can't detect from the callee-side whether it had been enabled on the caller-side (especially if they're from different units).

Regards,
Sven

Reply by email

Martin Frb
to Sven Barth
Sven Barth wrote 5 lines
Also it would be best to simply document as UTF8Copy working 1-based because you can't detect from the callee-side whether it had been enabled on the caller-side (especially if they're from different units).

Just an idea.

Maybe having 2 underlying string types for 0 and 1 based. Then it would be possible to use overload.

Btw, "from the calling side", before I search the doc, what happens if

Unit1 // has 0 base strings
var foo: ansistring; //global
foo := 'abc';

unit2 // has 1 based strings
writeln(foo[1]);  // follows 1 based or follows declaration 0 based?

Reply by email

Kazantsev Alexey
to Bart: Is this a known issue? === program z; {$longstrings on} {$zerobasedstrings on} var S, T:…
Show quoted text 9 lines
Hi, Is this a known issue? Outputs: S[0] = "A" [Ok] S[1] = "B" [Ok] S[2] = "C" [Ok] Copy(S,0,1) = "A" [Ok] Copy(S,1,1) = "A", FAIL: expected: B

In the Delphi {$zerobasedstrings on/off} :

1. String's intrinsic functions as Copy, Insert, Delete, etc used always 1-based indexing.
2. StringHelper's functions s.Copy, s.Insert, s.Delete etc used always 0-based indexing.
3. Only direct char indexing s[n] depends on {$zerobasedstrings} directive.

Kazantsev Alexey

Reply by email

Marco van de Voort
to Martin Frb: Just an idea. Maybe having 2 underlying string types for 0 and 1 based. Then it would be…

Op 7-4-2025 om 08:13 schreef Martin Frb via fpc-devel:

Show quoted text 11 lines
On 07/04/2025 08:01, Sven Barth via fpc-devel wrote: > > Also it would be best to simply document as UTF8Copy working 1-based > because you can't detect from the callee-side whether it had been > enabled on the caller-side (especially if they're from different units). > Just an idea. Maybe having 2 underlying string types for 0 and 1 based. Then it would be possible to use overload.

It is a delphi compatibility feature, to recycle mobile oriented code built with earlier Delphi versions. Afaik they later downplayed, so I'm not sure if there is new code written for this convention. (I don't do mobile development with Delphi, so I'm not sure)

IMHO it is a feature better forgotten.

Reply by email

Sven Barth
to Martin Frb: Just an idea. Maybe having 2 underlying string types for 0 and 1 based. Then it would be…

Martin Frb via fpc-devel schrieb am Mo.,
7. Apr. 2025, 08:13:

Show quoted text 12 lines
On 07/04/2025 08:01, Sven Barth via fpc-devel wrote: > > Also it would be best to simply document as UTF8Copy working 1-based > because you can't detect from the callee-side whether it had been > enabled on the caller-side (especially if they're from different units). > Just an idea. Maybe having 2 underlying string types for 0 and 1 based. Then it would be possible to use overload.

No. This would not be compatible with Delphi from which this feature stems.

Show quoted text 9 lines
Btw, "from the calling side", before I search the doc, what happens if Unit1 // has 0 base strings var foo: ansistring; //global foo := 'abc'; unit2 // has 1 based strings writeln(foo[1]); // follows 1 based or follows declaration 0 based?

It has nothing to do with the declaration. It's a local switch that controls whether a 1 is implicitly added by the compiler when accessing a string using [] accesses or intrinsics.

Regards,
Sven

Reply by email

Stefan Glienke
to Bart

No because the feature is related to the state of the ZBS switch at the source code location, not to the string instance.

Show quoted text 18 lines
On 07/04/2025 19:40 CEST Bart via fpc-devel wrote: On Mon, Apr 7, 2025 at 1:12 PM Marco van de Voort via fpc-devel wrote: > IMHO it is a feature better forgotten. +1, it's an abomination IMHO ;-) Out of curiosity: could the zerobased-ness of the string be stored in the string's "header"? -- Bart _______________________________________________ fpc-devel maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Sven Barth
to Bart

Bart via fpc-devel schrieb am Di., 8. Apr.
2025, 22:20:

Show quoted text 15 lines
On Tue, Apr 8, 2025 at 12:09 AM Sven Barth via fpc-devel wrote: >> > Please report a bug. >> Done: https://gitlab.com/freepascal.org/fpc/source/-/issues/41228 > > > Turns out I had been too eager to request a bug report. But thank you nevertheless. 😅 Well, similar off-by-one inconsistencies exist for Delete() and Insert(). It seems to be Delphi compatible??

Correct.

They've gone mad at Embarcadero. I'ld love to see someone try to make a Lazarus app usng this directive ;-)

Well, the point seems to be to use the helper types instead of the intrinsics then 🤷‍♀️

Regards,
Sven

Reply by email