Sign in Join

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

Mailing lists / fpc-devel / 2013-12

Encoded AnsiString

52 messages · 9 people · –

Reply by email Subscribe to this list Your subscription

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

Hans-Peter Diettrich

Inspired by the current Lazarus discussion I'd like to learn more about the current state of the implementation of the new AnsiStrings.

In case nothing has be done yet, I'd suggest to extend TAnsiRec by the new codePage and elemSize fields (words). These can be zero for now, so that the remaining codebase is not affected. Then it will be possible to play around with encoded strings, using the codePage field.

A related question:
Why is the string length set to zero in NewAnsiString, when the allocated Length is already known?

DoDi

Reply by email

Michael Van Canneyt
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 8 lines
Inspired by the current Lazarus discussion I'd like to learn more about the current state of the implementation of the new AnsiStrings. In case nothing has be done yet, I'd suggest to extend TAnsiRec by the new codePage and elemSize fields (words). These can be zero for now, so that the remaining codebase is not affected. Then it will be possible to play around with encoded strings, using the codePage field.

All this is done already a long time ago in trunk. We're way past that stage.

Current stage is the creation of a unicode RTL, where all base file/string operations accept unicode strings. This is done too.

Next step is creation of the unicode RTL, where "string" = "widestring". This will be combined with the dotted unit filenames, to be Delphi 2010+ compatible.

To allow people to choose, 2 RTLs will be created: one unicode (string=ansistring), one non-unicode (string=widestring).

This will result (probably) in 2 paths:
units/os-cpu
units/os-cpu-unicode
This is not decided yet.

I planned the work in februari/march.

A related question: Why is the string length set to zero in NewAnsiString, when the allocated Length is already known?

Because the allocated memory length is not necessarily equal to the string length. If you have a string of length 50, setting the length to 25 will not discard and reallocate the memory block, but merely set the character length to 25.

Michael.

Reply by email

Hans-Peter Diettrich
to Michael Van Canneyt
Show quoted text 15 lines
On Sun, 29 Dec 2013, Hans-Peter Diettrich wrote: > Inspired by the current Lazarus discussion I'd like to learn more > about the current state of the implementation of the new AnsiStrings. > > In case nothing has be done yet, I'd suggest to extend TAnsiRec by the > new codePage and elemSize fields (words). These can be zero for now, > so that the remaining codebase is not affected. Then it will be > possible to play around with encoded strings, using the codePage field. > All this is done already a long time ago in trunk. We're way past that stage.

I'm very confused, didn't use FPC for a long time. Have to refresh memory of all related procedures...

How do I instruct fpcup to checkout the trunk version? (Windows) I tried to add an parameter fpcURL=trunk to the shortcut, is this correct?

How do I proceed (build, use in Lazarus...)?
Any links appreciated :-)

Show quoted text 6 lines
Current stage is the creation of a unicode RTL, where all base file/string operations accept unicode strings. This is done too. Next step is creation of the unicode RTL, where "string" = "widestring". This will be combined with the dotted unit filenames, to be Delphi 2010+ compatible.

<sigh.sigh>
How do I create source files for use with both versions?

Show quoted text 9 lines
To allow people to choose, 2 RTLs will be created: one unicode (string=ansistring), one non-unicode (string=widestring). This will result (probably) in 2 paths: units/os-cpu units/os-cpu-unicode This is not decided yet. I planned the work in februari/march.

Thanks :-)

Where can I jump in?

Show quoted text 9 lines
> A related question: > Why is the string length set to zero in NewAnsiString, when the > allocated Length is already known? Because the allocated memory length is not necessarily equal to the string length. If you have a string of length 50, setting the length to 25 will not discard and reallocate the memory block, but merely set the character length to 25.

This means that the allocated length is stored somewhere else, in the memory block descriptor?

How can a user request an string of a specific allocation size?

Another one:

I've heard that a mix of encodings converts the (concatenated) output (RawByteString?) to CP_ACP, with possible losses. Is this correct?

DoDi

Reply by email

Marco van de Voort
to Michael Van Canneyt: All this is done already a long time ago in trunk. We're way past that stage. Current…

In our previous episode, Michael Van Canneyt said:

Show quoted text 6 lines
Current stage is the creation of a unicode RTL, where all base file/string operations accept unicode strings. This is done too. Next step is creation of the unicode RTL, where "string" = "widestring". This will be combined with the dotted unit filenames, to be Delphi 2010+ compatible.

If the dotted stuff is ready, as an excercise, the windows unit could be switched to the scheme.

Btw, and it is unicodestring, not widestring.

Reply by email

Michael Van Canneyt
to Hans-Peter Diettrich: I'm very confused, didn't use FPC for a long time. Have to refresh memory of all related…
Hans-Peter Diettrich wrote 25 lines
Michael Van Canneyt schrieb: > > > On Sun, 29 Dec 2013, Hans-Peter Diettrich wrote: > >> Inspired by the current Lazarus discussion I'd like to learn more about >> the current state of the implementation of the new AnsiStrings. >> >> In case nothing has be done yet, I'd suggest to extend TAnsiRec by the new >> codePage and elemSize fields (words). These can be zero for now, so that >> the remaining codebase is not affected. Then it will be possible to play >> around with encoded strings, using the codePage field. >> > > All this is done already a long time ago in trunk. > We're way past that stage. I'm very confused, didn't use FPC for a long time. Have to refresh memory of all related procedures... How do I instruct fpcup to checkout the trunk version? (Windows) I tried to add an parameter fpcURL=trunk to the shortcut, is this correct? How do I proceed (build, use in Lazarus...)? Any links appreciated :-)

No idea.

Show quoted text 10 lines
> Current stage is the creation of a unicode RTL, where all base file/string > operations accept unicode strings. This is done too. > > Next step is creation of the unicode RTL, where "string" = "widestring". > This will be combined with the dotted unit filenames, to be Delphi 2010+ > compatible. <sigh.sigh> How do I create source files for use with both versions?

What do you mean by this statement ?

Show quoted text 13 lines
> To allow people to choose, 2 RTLs will be created: one unicode > (string=ansistring), one non-unicode (string=widestring). > > This will result (probably) in 2 paths: > units/os-cpu > units/os-cpu-unicode > This is not decided yet. > > I planned the work in februari/march. Thanks :-) Where can I jump in?

When I'm done I will release a version for testing to the public.

Show quoted text 12 lines
>> A related question: >> Why is the string length set to zero in NewAnsiString, when the allocated >> Length is already known? > > Because the allocated memory length is not necessarily equal to the string > length. > If you have a string of length 50, setting the length to 25 will not > discard and reallocate the memory block, but merely set the character > length to 25. This means that the allocated length is stored somewhere else, in the memory block descriptor?

Yes.

How can a user request an string of a specific allocation size?

You should not. But if you absolutely want that: Look up TAnsiRec and do

SetLength(S,AllocationLength-SizeOf(TAnsiRec));

Don't rely on this. Messing with internals is always a bad idea. That is why TAnsiRec is an internal type, not exposed. To prevent people (like you, seemingly) from messing with internals.

Show quoted text 6 lines
Another one: I've heard that a mix of encodings converts the (concatenated) output (RawByteString?) to CP_ACP, with possible losses. Is this correct?

Define "output" ?

Michael.

Reply by email

Jonas Maebe
to Hans-Peter Diettrich: I'm very confused, didn't use FPC for a long time. Have to refresh memory of all related…
Hans-Peter Diettrich wrote
I've heard that a mix of encodings converts the (concatenated) output (RawByteString?) to CP_ACP, with possible losses. Is this correct?

The code page of ansistrings concatenations is the code page of the result to which this concatenation is assigned/converted. For rawbytestring, this code page is CP_ACP per Delphi compatibility.

I'm inclined to add a global boolean variable to the system unit that allows changing this behaviour so that it uses CP_UTF8 instead in such cases (defaulting to false, for Delphi compatibility). In practice, setting it to true shouldn't cause problems even with virtually all Delphi, as routines that work with rawbytestring should be able to handle any code page anyway.

Jonas

Reply by email

Hans-Peter Diettrich
to Michael Van Canneyt: No idea. What do you mean by this statement ? When I'm done I will release a version for…
Show quoted text 11 lines
On Sun, 29 Dec 2013, Hans-Peter Diettrich wrote: >> This will be combined with the dotted unit filenames, to be Delphi >> 2010+ compatible. > > <sigh.sigh> > How do I create source files for use with both versions? What do you mean by this statement ?

I'm not familiar with dotted unit names, they seem not to be used in XE. So I only can imagine something like conditionals around the different items in un/dotted environment, to keep "Classes" separate from "System.Classes"?

Are directories involved? If so, does the Delphi structure match the FPC tree structure?

> Where can I jump in? When I'm done I will release a version for testing to the public.

Fine :-)

> How can a user request an string of a specific allocation size? You should not.

Okay.

Show quoted text 6 lines
> Another one: > > I've heard that a mix of encodings converts the (concatenated) output > (RawByteString?) to CP_ACP, with possible losses. Is this correct? Define "output" ?
s := SomeACPstr+SomeUTF8str+"äöü";

In XE I can concatenate ACP and UTF-8 strings and assign it to an OEM string without losses. Somebody said this will fail in FPC, on e.g.

   FindFirst(myPath+allfiles,faAnyFile,sr);

due to an (intermediate?) conversion of myPath+allfiles to CP_ACP.

Of course the string must be converted to CP_ACP if FindFirst expects exactly an AnsiString(0) argument, otherwise something is broken.

DoDi

Reply by email

Hans-Peter Diettrich
to Jonas Maebe: The code page of ansistrings concatenations is the code page of the result to which this…
The code page of ansistrings concatenations is the code page of the result to which this concatenation is assigned/converted. For rawbytestring, this code page is CP_ACP per Delphi compatibility.

This does not match my experience with Delphi XE :-(

Can you give an Delphi example, so that I can verify this behaviour?

Show quoted text 6 lines
I'm inclined to add a global boolean variable to the system unit that allows changing this behaviour so that it uses CP_UTF8 instead in such cases (defaulting to false, for Delphi compatibility). In practice, setting it to true shouldn't cause problems even with virtually all Delphi, as routines that work with rawbytestring should be able to handle any code page anyway.

The Result of an f(...):RawByteString should return an string of that encoding, that results from its construction.

My view on RawByteString:

1) This type serves as a collector for AnsiStrings of any encoding, where otherwise a conversion into UTF-16 (string) or CP_ACP (AnsiString) were required.

2) Variables of type RawByteString are intended only as *local* variables, inside subroutines dealing with RawByteStrings.

3) Functions accepting RawByteStrings can provide fast results, when the encoding of the string arguments is the same, otherwise they have to use Unicode (UTF-8/16) for intermediate results.

Rationale/observations:

[1] Delphi: Only UTF-16 and CP_ACP are explicitly supported in overloaded stringhandling functions. This would require to convert all string arguments other than AnsiString(0) into UTF-16. A RawByteString overload (instead of AnsiString(0)) allows to process an AnsiString(x) without UTF-16 conversion, when the function code and argument encodings do not require such a conversion. Otherwise the RawByteString overloads convert all strings into UTF-16 internally, and back again into a RawByteString Result. Since UTF-8 is not a specifically supported encoding, UTF-16 must be converted back to CP_ACP instead, with possible losses.

In fact the AnsiString(0) overloads in AnsiStrings.pas are another optimization, that does not check the encoding of the string arguments, eventual conversions are assumed to be performed before. This leads to errors when the declared (static) string type of an parameter does not match its actual (dynamic) encoding. Such irregular strings can be constructed by wrong/unexpected use of RawByteString. Example (XE):

var a: AnsiString; u: UTF8String;
function cpy(s: RawByteString):RawByteString;
begin Result := s; end;
a := cpy(u); //now a has encoding UTF-8!

Here the XE compiler omits the conversion of the RawByteString result to the declared encoding of the target. Dunno about newer versions.

[3] Delphi: since the only explicitly supported lossless encoding is UTF-16, RawByteString stringhandling functions with arguments of mixed encodings must be converted to UTF-16, finally back to AnsiString. Here a conversion to CP_ACP may occur, when/because the further use of a RawByteString result is unknown. Delphi does not provide UTF-8 overloads, so that this encoding cannot be used when an UnicodeString has to be converted into an RawByteString.

FPC: when UTF-8 is used inside RawByteString routines, instead of UTF-16, the RawByteString result can have exactly this encoding, for lossless handling in further calls, until the result finally is assigned to a variable/parameter of a fixed encoding. In detail no conversion to CP_ACP is required when UTF-8 is a supported by overloads, or as a special case of RawByteString arguments.

So IMO there exists no *requirement*, that intermediate Unicode strings have to be converted to CP_ACP as RawByteString Results. This is only a fatal consequence of the crippled Delphi handling of encodings (disregarding UTF-8), with possible conversion losses. When UTF-8 is used for intermediate Unicode strings, the RawByteString results can preserve lossless UTF-8 encoding.

DoDi

Reply by email

Sven Barth
to Hans-Peter Diettrich: I'm not familiar with dotted unit names, they seem not to be used in XE. So I only can…
Hans-Peter Diettrich wrote 18 lines
Michael Van Canneyt schrieb: > > > On Sun, 29 Dec 2013, Hans-Peter Diettrich wrote: >>> This will be combined with the dotted unit filenames, to be Delphi >>> 2010+ compatible. >> >> <sigh.sigh> >> How do I create source files for use with both versions? > > What do you mean by this statement ? I'm not familiar with dotted unit names, they seem not to be used in XE. So I only can imagine something like conditionals around the different items in un/dotted environment, to keep "Classes" separate from "System.Classes"?

Dotted unit names are supported at least since Delphi 2007 (maybe also from 2005 on), but they weren't extensively used back then (look at Collections.Generics for an example). Only XE2 did use it extensively which was also when support for default namespaces were added. With XE2 the RTL units were put into a System namespace, the VCL units were put into a VCL namespace and the newly added FireMonkey units were added to a FMX namespace. The usage of default namespaces (System and VCL in case of a VCL application) allows the usage of backwards compatible single identifier unit names.

Are directories involved? If so, does the Delphi structure match the FPC tree structure?

No directories are involved, it's just the naming.

Regards,
Sven

Reply by email

Sven Barth
to Hans-Peter Diettrich: This does not match my experience with Delphi XE :-( Can you give an Delphi example, so…
Hans-Peter Diettrich wrote 9 lines
Jonas Maebe schrieb: > The code page of ansistrings concatenations is the code page of the > result to which this concatenation is assigned/converted. For > rawbytestring, this code page is CP_ACP per Delphi compatibility. This does not match my experience with Delphi XE :-( Can you give an Delphi example, so that I can verify this behaviour?

=== code begin ===

program tstrtest;
{$apptype console}
procedure Test(aArg: RawByteString);
begin
   Writeln(StringCodePage(aArg));
end;
type
   CP1252String = type AnsiString(1252);
var
   s1: UTF8String;
   s2: CP1252String;
begin
   s1 := 'Test';
   s2 := 'Test';
   DefaultSystemCodePage := 1251;
   Test(s1);
   Test(s2);
   Test(s1 + s2);
end.

=== code end ===

This will print

=== output begin ===

65001
1252
1251

=== output end ===

This was tested using Delphi XE (it might not compile though as I've just rewritten the code from memory as the original is on a different computer)

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Jonas Maebe: The code page of ansistrings concatenations is the code page of the result to which this…
Show quoted text 6 lines
I'm inclined to add a global boolean variable to the system unit that allows changing this behaviour so that it uses CP_UTF8 instead in such cases (defaulting to false, for Delphi compatibility). In practice, setting it to true shouldn't cause problems even with virtually all Delphi, as routines that work with rawbytestring should be able to handle any code page anyway.

Sounds good, but I fear complications because such a global variable will affect also library behaviour. When UTF-8 is used in Lazarus or for filenames, and this encoding doesn't work in combination with string literals (CP_ACP?), then the Delphi default is not acceptable. When string literals are assumed as UTF-8, they won't work with strings of CP_ACP or other encodings, for the same reason.

I'd restrict strict Delphi compatibility to string=UnicodeString, if ever, and leave the UTF-8 RTL and LCL unaffected by the Delphi flaw. But what's Delphi compatibility worth without a UTF-16 LCL?

DoDi

Reply by email

Hans-Peter Diettrich
to Sven Barth: === code begin === program tstrtest; {$apptype console} procedure Test(aArg:…

Sven Barth schrieb:

[...]

This was tested using Delphi XE (it might not compile though as I've just rewritten the code from memory as the original is on a different computer)

Thanks, the code is okay, and it produces the expected results. The compiler also warns about a downcast from 'string' to 'RawByteString'.

Then I tested some adds:

When s1+s2 is assigned to an UTF-8 variable, the compiler also warns about an downcast from 'string' to 'UTF8String', and that's ridiculous. Either the conversion from UTF-16 to UTF-8 is flawed, or the warning is wrong.

When I write a
   function conc(s1,s2: RawByteString): RawByteString;
   begin Result := s1+s2; end;
then
   test(conc(s1,s2));
detects CP 65001 (UTF-8)!

The same when conc is redeclared as

   function conca(s1,s2: RawByteString): AnsiString;
   begin Result := s1+s2; end;

also detects CP 65001 (UTF-8), where the function should return a CP_ACP (1251) result.

BTW both conc and conca do not produce compiler warnings.

Do you think that FPC should really reproduce all this inconsistent behaviour? Who would test or even specify the compatible behaviour, when every new variation will result in more unexpected results? IMO it's much easier to do it right, and fix the Delphi flaws in FPC.

DoDi

Reply by email

Paul Ishenin
to Hans-Peter Diettrich

30.12.2013 9:07, Hans-Peter Diettrich пишет:

Do you think that FPC should really reproduce all this inconsistent behaviour? Who would test or even specify the compatible behaviour, when every new variation will result in more unexpected results? IMO it's much easier to do it right, and fix the Delphi flaws in FPC.

The work is already done by FPC team. AnsiString(codepage) works and works compatible with Delphi (whether someone like this or not) and the behavior is covered by tests. Trunk version is very close to 2.8 release. The only related thing which we thought to touch before the release was resourcestring handling. If I have some free time during the new year holidays I will how one can help at this stage:

1. Check related FPC tests and write new for the missing cases.
2. Compare FPC and Delphi RTL classes which had beed adjusted in Delphi during the unicodestring move and check whether something minor can be added to FPC.

All major changes like the new TStringList class based on UnicodeString should wait for 2.8 release.

Best regards,
Paul Ishenin

Reply by email

Hans-Peter Diettrich
to Paul Ishenin
Show quoted text 10 lines
30.12.2013 9:07, Hans-Peter Diettrich пишет: > Do you think that FPC should really reproduce all this inconsistent > behaviour? Who would test or even specify the compatible behaviour, > when every new variation will result in more unexpected results? IMO > it's much easier to do it right, and fix the Delphi flaws in FPC. The work is already done by FPC team. AnsiString(codepage) works and works compatible with Delphi (whether someone like this or not) and the behavior is covered by tests. Trunk version is very close to 2.8 release.

This means that UTF-8 won't work properly when it's not CP_ACP :-(

DoDi

Reply by email

Michael Van Canneyt
to Paul Ishenin: 30.12.2013 9:07, Hans-Peter Diettrich пишет: The work is already done by FPC team.…
Paul Ishenin wrote 22 lines
30.12.2013 9:07, Hans-Peter Diettrich пишет: > Do you think that FPC should really reproduce all this inconsistent > behaviour? Who would test or even specify the compatible behaviour, when > every new variation will result in more unexpected results? IMO it's much > easier to do it right, and fix the Delphi flaws in FPC. The work is already done by FPC team. AnsiString(codepage) works and works compatible with Delphi (whether someone like this or not) and the behavior is covered by tests. Trunk version is very close to 2.8 release. The only related thing which we thought to touch before the release was resourcestring handling. If I have some free time during the new year holidays I will look at it. So how one can help at this stage: 1. Check related FPC tests and write new for the missing cases. 2. Compare FPC and Delphi RTL classes which had beed adjusted in Delphi during the unicodestring move and check whether something minor can be added to FPC. All major changes like the new TStringList class based on UnicodeString should wait for 2.8 release.

I don't think that this is a good idea, it means that e.g. TStrings.SaveToFile() or TFileStream.Create() is still crippled. Better bite the bullet. This is what I wanted to test in feb/march.

Michael.

Reply by email

Jy V
to Hans-Peter Diettrich: This does not match my experience with Delphi XE :-( Can you give an Delphi example, so…
Hans-Peter Diettrich wrote 9 lines
var a: AnsiString; u: UTF8String; function cpy(s: RawByteString):RawByteString; begin Result := s; end; a := cpy(u); //now a has encoding UTF-8! Here the XE compiler omits the conversion of the RawByteString result to the declared encoding of the target. Dunno about newer versions.

A quick note: the new LLVM Delphi compiler forbid the use of AnsiString and AnsiChar, (declared in the unit AnsiString.pas, you cannot use this unit anyway),
you will probably choose to hack using MarshaledAString.

Reply by email

Paul Ishenin
to Michael Van Canneyt: I don't think that this is a good idea, it means that e.g. TStrings.SaveToFile() or…

30.12.2013 18:33, Michael Van Canneyt пишет:

Show quoted text 14 lines
> > So how one can help at this stage: > > 1. Check related FPC tests and write new for the missing cases. > 2. Compare FPC and Delphi RTL classes which had beed adjusted in > Delphi during the unicodestring move and check whether something > minor can be added to FPC. > > All major changes like the new TStringList class based on > UnicodeString should wait for 2.8 release. I don't think that this is a good idea, it means that e.g. TStrings.SaveToFile() or TFileStream.Create() is still crippled. Better bite the bullet. This is what I wanted to test in feb/march.

This will also mean that we will release 2.8 much later (looking at cpstr development speed probably few years later) because together with this implementation we need to solve ansi/unicode RTL problem (dotted unit names in RTL and packages).

Imo it is better to release all that huge changes we have in trunk as is (maybe together with resourcestring solution). Then with the following minor releases we improve dotted unit names support (like default namespaces) together with experiments for ansi/unicode RTL.

Best regards,
Paul Ishenin

Reply by email

Michael Van Canneyt
to Paul Ishenin
Paul Ishenin wrote 25 lines
30.12.2013 18:33, Michael Van Canneyt пишет: >> >> So how one can help at this stage: >> >> 1. Check related FPC tests and write new for the missing cases. >> 2. Compare FPC and Delphi RTL classes which had beed adjusted in Delphi >> during the unicodestring move and check whether something minor can be >> added to FPC. >> >> All major changes like the new TStringList class based on UnicodeString >> should wait for 2.8 release. > > I don't think that this is a good idea, it means that e.g. > TStrings.SaveToFile() or TFileStream.Create() is still crippled. Better > bite the bullet. This is what I wanted to test in feb/march. This will also mean that we will release 2.8 much later (looking at cpstr development speed probably few years later) because together with this implementation we need to solve ansi/unicode RTL problem (dotted unit names in RTL and packages). Imo it is better to release all that huge changes we have in trunk as is (maybe together with resourcestring solution). Then with the following minor releases we improve dotted unit names support (like default namespaces) together with experiments for ansi/unicode RTL.

I think I understand what you want to say:
Release the codepage strings support with the RTL as-is.

But the "experiments for ansi/unicode RTL" are already in trunk. Do you plan to take them out ?

and:
What good is having the unicode string support if none of the classes or units make use of it ? No-one will test it or even be able to test it because none of the base classes/routines are adapted to it.

Michael.

Reply by email

Paul Ishenin
to Michael Van Canneyt
Michael Van Canneyt wrote
But the "experiments for ansi/unicode RTL" are already in trunk. Do you plan to take them out ?

By "experiments" I ment having 2 (or 1.5) RTL with unicode + ansi classes which we planned to solve using namespaces.

What good is having the unicode string support if none of the classes or units make use of it ? No-one will test it or even be able to test it because none of the base classes/routines are adapted to it.

We have string, file and console routings for use and testing.

Best regards,
Paul Ishenin

Reply by email

Marco van de Voort
to Paul Ishenin: 30.12.2013 18:33, Michael Van Canneyt пишет: This will also mean that we will…

In our previous episode, Paul Ishenin said:

Show quoted text 13 lines
> I don't think that this is a good idea, it means that e.g. > TStrings.SaveToFile() or TFileStream.Create() is still crippled. > Better bite the bullet. This is what I wanted to test in feb/march. This will also mean that we will release 2.8 much later (looking at cpstr development speed probably few years later) because together with this implementation we need to solve ansi/unicode RTL problem (dotted unit names in RTL and packages). Imo it is better to release all that huge changes we have in trunk as is (maybe together with resourcestring solution). Then with the following minor releases we improve dotted unit names support (like default namespaces) together with experiments for ansi/unicode RTL.

Having a base classes implementation that is unicode capable, can help with e.g. fixing up TProcess to unicode over the 2.8 lifecycle and other simple but crucial packages, and maybe even pioneer with fcl-db.

Doing this after the 2.8 branch makes trunk and fixes immediately incompatible, which would make 2.8 quite an orphan.

Reply by email

Marco van de Voort
to Michael Van Canneyt: I think I understand what you want to say: Release the codepage strings support with the…

In our previous episode, Michael Van Canneyt said:

Show quoted text 6 lines
But the "experiments for ansi/unicode RTL" are already in trunk. Do you plan to take them out ? and: What good is having the unicode string support if none of the classes or units make use of it ?

Limited. But 2.8.x is not all about unicode. Still, if you have planned time, it might be worth to try it IMHO.

Reply by email

Michael Van Canneyt
to Marco van de Voort
Marco van de Voort wrote 10 lines
In our previous episode, Michael Van Canneyt said: > But the "experiments for ansi/unicode RTL" are already in trunk. > Do you plan to take them out ? > > and: > What good is having the unicode string support if none of the classes or > units make use of it ? Limited. But 2.8.x is not all about unicode. Still, if you have planned time, it might be worth to try it IMHO.

That was my idea.

If it turns out to be really impossible, we can still do as Paul suggests, but if it works, I would attempt to release 2.8 with dotted units.

In each case, the ground work will be done in a branch, so as not to irreversibly damage trunk and destroy Paul's dreams :)

Let's see how well I fare; 2.8.0 is not for next month anyway. First get 2.6.4 out of the door.

Michael.

Reply by email

Paul Ishenin
to Michael Van Canneyt
Michael Van Canneyt wrote 8 lines
That was my idea. If it turns out to be really impossible, we can still do as Paul suggests, but if it works, I would attempt to release 2.8 with dotted units. In each case, the ground work will be done in a branch, so as not to irreversibly damage trunk and destroy Paul's dreams :)

I have nothing against if you think there are no risks to delay the release for more than a year.

Let's see how well I fare; 2.8.0 is not for next month anyway. First get 2.6.4 out of the door.

Best regards,
Paul Ishenin

Reply by email

Michael Schnell
to Michael Van Canneyt: All this is done already a long time ago in trunk. We're way past that stage. Current…
Michael Van Canneyt wrote
We're way past that stage.

Sorry, but IMHO freezing the current (supposedly DXE compatible) state does not make much sense.

To decently support creating fully portable applications for multiple OSes, "TStrings" and its siblings (e.g. TStringlist") needs do be implemented in a way not forcing a fixed encoding to store the information in and thus force time consuming convention when storing and retrieving strings in any different encoding.

-Michael

Reply by email

Michael Van Canneyt
to Michael Schnell
Michael Schnell wrote 12 lines
On 12/29/2013 10:57 AM, Michael Van Canneyt wrote: > > We're way past that stage. Sorry, but IMHO freezing the current (supposedly DXE compatible) state does not make much sense. To decently support creating fully portable applications for multiple OSes, "TStrings" and its siblings (e.g. TStringlist") needs do be implemented in a way not forcing a fixed encoding to store the information in and thus force time consuming convention when storing and retrieving strings in any different encoding.

We know this. But that is stage 2.

Michael.

Reply by email

Michael Schnell
to Hans-Peter Diettrich: This does not match my experience with Delphi XE :-( Can you give an Delphi example, so…
Hans-Peter Diettrich wrote
My view on RawByteString:

My view on RawByteString originally had been that it can hold strings of any encoding and the software that gets such a variable (or function argument) can detect the actual encoding and behave accordingly. Thus "dynamically generic" functions can be done, handling any encoding style which is very appropriate as there can be sensible functionalists that don't need to know the encoding at all or not in detail (such as "blindly" storing and retrieving the information, concatenating, ...).

But I (not owning XE) learned that this is not the case with XE, so maybe inventing a differently name string subtype might be appropriate.

-Michael

Reply by email

Michael Schnell
to Jy V: On Sun, Dec 29, 2013 at 7:26 PM, Hans-Peter Diettrich A quick note: the new LLVM Delphi…
Jy V wrote
A quick note: the new LLVM Delphi compiler forbid the use of AnsiString and AnsiChar,

Yuck !

Forking the platforms in that incompatible way a really ugly move of Delphi's. Hopefully fpc (and Lazarus) is able to continue it's path to real source code compatibility between all supported platforms.

Thanks to the developers for their great effort !
-Michael

Reply by email

Michael Schnell
to Michael Van Canneyt: We know this. But that is stage 2. Michael.
Michael Van Canneyt wrote
We know this. But that is stage 2.

Sounds great !

Could you elaborate those plans ?

I fear that releasing "stage 1" to the public might introduce another source of incompatibility.

Explanation: My horror-scenario when trying to convince my colleagues to port their (huge) "embedded" Delphi application to Lazarus:

- They had it nicely working in pre-Unicode Delphi. It would be possible to port it to pre-Unicode Lazarus with decent effort.

- It took them a huge effort to port it to Unicode enabled Delphi (including managing the glitches of multiple Delphi versions).

- Current Unicode aware (UTF-8 enabled) Lazarus is compatible to neither of pre-Unicode Delphi nor to Unicode-aware Delphi, Hence using it for porting is out of question.

- "just Delphi XE compatible" "Stage 1" might be a valid target, in case Lazarus is done appropriately. but I supposedly would recommend waiting for "Stage 2" as some of the porting effort might be done in vain regarding the goodies "Stage 2" promises. (Not regarding additional issues that might come up when migrating from "Stage 1" to "State 2".)

- of course "Stage 2" would be most appropriate, but only if Lazarus follows accordingly,

(I suppose at that time the "natural" target arch will be ARM 64 :-) ) -Michael

Reply by email

Michael Van Canneyt
to Michael Schnell
Michael Schnell wrote 7 lines
On 01/07/2014 10:41 AM, Michael Van Canneyt wrote: > > We know this. But that is stage 2. > Sounds great ! Could you elaborate those plans ?

There is not much to say.

There will be 2 sets of units:
* Unicode
* AnsiString

for unicode, there is no problem, since everything is 2 bytes (ignoring some exotic codepoints here) so string encoding does not apply.

for ansistring, string=ansistring, there are some encoding issues, but the RTL is capable of using Widestrings for all OS interface routines.

Michael.

Reply by email

Jonas Maebe
to Michael Van Canneyt
Michael Van Canneyt wrote
There will be 2 sets of units: * Unicode * AnsiString

Or they may be integrated to a large extent. This has not yet been decided. In any case, creating two separate sets of units is a good step regardless of what happens eventually, since we need the functionality of both in any case.

Jonas

Reply by email

Michael Schnell
to Michael Van Canneyt: There is not much to say. There will be 2 sets of units: * Unicode * AnsiString for…
Michael Van Canneyt wrote 12 lines
There is not much to say. There will be 2 sets of units: * Unicode * AnsiString for unicode, there is no problem, since everything is 2 bytes (ignoring some exotic codepoints here) so string encoding does not apply. for ansistring, string=ansistring, there are some encoding issues, but the RTL is capable of using Widestrings for all OS interface routines.

This might help in a certain way, but defining a decently dynamic string subtype and use same for TStringList would allow for a lot more flexibility / functionality. (Together with eliminating the ambiguous naming "ANSI...")

-Michael

Reply by email

Michael Van Canneyt
to Michael Schnell: This might help in a certain way, but defining a decently dynamic string subtype and use…
Michael Schnell wrote 17 lines
On 01/07/2014 11:22 AM, Michael Van Canneyt wrote: > > There is not much to say. > > There will be 2 sets of units: > * Unicode > * AnsiString > > for unicode, there is no problem, since everything is 2 bytes (ignoring > some exotic codepoints here) so string encoding does not apply. > > for ansistring, string=ansistring, there are some encoding issues, but the > RTL is capable of using Widestrings for all OS interface routines. This might help in a certain way, but defining a decently dynamic string subtype and use same for TStringList would allow for a lot more flexibility / functionality. (Together with eliminating the ambiguous naming "ANSI...")

TRawByteString is what you need.

Michael.

Reply by email

Michael Schnell
to Michael Van Canneyt
Michael Van Canneyt wrote
TRawByteString is what you need.

AFAI was told by DXE users, this is not true. That is why i did not test this yet. But as you state otherwise I will check into that.

But anyway this does not help, as long as the RTL (especially TStrings, TStringList) does not use such type, but forces a fixed type and thus unnecessary conversions in and out. (there have been several discussion on that, including how to implement decent encoding-checks in the compiler, and performance issues).

-Michael

Reply by email

Michael Van Canneyt
to Michael Schnell
Michael Schnell wrote 11 lines
On 01/07/2014 11:48 AM, Michael Van Canneyt wrote: > TRawByteString is what you need. > AFAI was told by DXE users, this is not true. That is why i did not test this yet. But as you state otherwise I will check into that. But anyway this does not help, as long as the RTL (especially TStrings, TStringList) does not use such type, but forces a fixed type and thus unnecessary conversions in and out. (there have been several discussion on that, including how to implement decent encoding-checks in the compiler, and performance issues).

We are well aware of that.

If you want a TStrings that can hold strings which may differ in their encoding (i.e. strings[0] has a different encoding from strings[1]) then you'll be left in the cold.

TStrings will not support that (unless maybe the rawbytestring type can be specified, I would need to check that).

Other than that, you can/must specify an encoding when creating the TStrings instance. As a consequence all strings you add will be checked for this encoding. This is only logical.

That said, if you have use-case 1 (which I doubt, since it is not possible even today) then you're better off using unicodestring anyway.

Michael.

Reply by email

Michael Schnell
to Michael Van Canneyt
Michael Van Canneyt wrote
if you have use-case 1 (which I doubt, since it is not possible even today) then you're better off using unicodestring anyway.

My argumentation is driven by the experience (some myself, a huge lot by my colleagues) with doing "embedded" M2M-communication projects with multiple protocols and applications (included in the project and/or predefined by customers) and with some programs requiring sophisticated user interaction in multiple languages.

The projects originally were done (mine still are done) using old pre-Unicode Delphi.

Here, strings are used as well to handle texts as to handle byte streams (that might contain binary data or might contain text in whatever encoding).

On top of that, the embedded handling of mass-data here needs to be very fast, handling multiple TCP/IP interfaces at the same time..

Here, of course, for binary strings 8 Bit characters are the only appropriate choice, while for the multi-language text supposedly the best choice is using the encoding the underlying OS offer (e.g. UTF-16 for Windows) throughout the multiple units of the project.

So we are burned regarding the flexibility and the pitfalls of using strings in multiple encoding variants within a single project, leading to the urgent request for allowing to use any TString sibling (in own code and in the RTL) in a way that allows for using arbitrary encoding without forced re-encoding under the hood, if not absolutely necessary.

-Michael

Reply by email

Michael Van Canneyt
to Michael Schnell
Michael Schnell wrote 16 lines
On 01/07/2014 12:27 PM, Michael Van Canneyt wrote: > > if you have use-case 1 (which I doubt, since it is not possible even today) > then you're better off using unicodestring anyway. My argumentation is driven by the experience (some myself, a huge lot by my colleagues) with doing "embedded" M2M-communication projects with multiple protocols and applications (included in the project and/or predefined by customers) and with some programs requiring sophisticated user interaction in multiple languages. The projects originally were done (mine still are done) using old pre-Unicode Delphi. Here, strings are used as well to handle texts as to handle byte streams (that might contain binary data or might contain text in whatever encoding).

This is a mistake. You should use TByteArray for that. "Old" pre-unicode Delphi also handles this type.

You cannot expect us to take into account your improper use of single-byte strings when designing a RTL.

You'll just have to see whether rawbytestring does what you need...

Michael.

Reply by email

Michael Schnell
to Michael Van Canneyt
Michael Van Canneyt wrote
This is a mistake. You should use TByteArray for that. "Old" pre-unicode Delphi also handles this type.

Of course I do know that this sometimes is recommended, but (with pre-Unicode Delphi) I don't see any point in not using "String", which is a lot more handy providing easy to use concatenation, search operation, etc.

With a new string type this would come for free, as it requires the same behavior as the "locale based 1 Byte ANSI String" encoding variant, which is necessary to be supported anyway.

Thus, IMHO, a discussion about TByteArray is pointless

-Michael

Reply by email

Michael Van Canneyt
to Michael Schnell
Michael Schnell wrote 14 lines
On 01/07/2014 01:05 PM, Michael Van Canneyt wrote: > > This is a mistake. You should use TByteArray for that. "Old" pre-unicode > Delphi also handles this type. Of course I do know that this sometimes is recommended, but (with pre-Unicode Delphi) I don't see any point in not using "String", which is a lot more handy providing easy to use concatenation, search operation, etc. With a new string type this would come for free, as it requires the same behavior as the "locale based 1 Byte ANSI String" encoding variant, which is necessary to be supported anyway. Thus, IMHO, a discussion about TByteArray is pointless

Maybe.

But like I said:
Do not expect us to adapt the RTL to suit any inappropriate use of strings.

Michael.

Reply by email

Michael Schnell
to Michael Van Canneyt
Michael Van Canneyt wrote
But like I said: Do not expect us to adapt the RTL to suit any inappropriate use of strings.

Like I said: I don't ! (With the requested behavior this comes for free as a side-effect.)

But I do expect decent handling of "locale based 1 Byte ANSI String" encoding variants (i.e. the functionality of pre-Unicode Delphi and of the current fpc) _at_the_same_timer_ as_and_combineable_with_ Unicode Strings (and at best additionally user-definable encoding schemes).

-Michael

Reply by email

Hans-Peter Diettrich
to Michael Van Canneyt: We are well aware of that. If you want a TStrings that can hold strings which may differ…
If you want a TStrings that can hold strings which may differ in their encoding (i.e. strings[0] has a different encoding from strings[1]) then you'll be left in the cold.

Just an idea:
What if FPC adds another encoding, similar to RawByteString ($FFFF), but without the Delphi quirks? Or simply fix the RawByteString flaws in the *Ansi* compiler and RTL?

1) In a discussion in the Embarcadero groups it turned out that, in an assignment of a RawByteString to another AnsiString type, the Delphi compiler should (but does not) check and eventually convert the string to the static encoding of the target. This is (almost) the only way to create strings with a different static and dynamic encoding.

2) The stupid conversion to CP_ACP in an assignment *to* an RawByteString should be dropped. This applies in detail to the assignment to *function results*.

3) The function result type should be honored, in functions accepting RawByteString parameters. The Delphi compiler seems to *assume* that the results of such functions is RawByteString, so that (including beforementioned flaws) the outcome is a CP_ACP string, even if the declared function result is e.g. an UTF8String.

Test case:
   function conc(a,b: RawByteString): UTF8String;
   begin Result := a+b; end;
The same result as for
   function conc(a,b: RawByteString): RawByteString;
   begin Result := a+b; end;
the returned string has CP_ACP encoding :-(

When these flaws are fixed in the FPC compiler, the AnsiString types will always have the same static and dynamic encoding, as it should be.

Then TStrings could be based on such RawByteStrings, without excess conversions or losses. Sorting (TStringList) eventually should ignore the dynamic encoding, i.e. work on a strictly binary (byte-by-byte) base.

DoDi

Reply by email

Michael Schnell
to Hans-Peter Diettrich: Just an idea: What if FPC adds another encoding, similar to RawByteString ($FFFF), but…
Hans-Peter Diettrich wrote
What if FPC adds another encoding, similar to RawByteString ($FFFF), but without the Delphi quirks? Or simply fix the RawByteString flaws in the *Ansi* compiler and RTL?

+1 (in fact I elaborated on that in some older Threads here)

Show quoted text 6 lines
1) In a discussion in the Embarcadero groups it turned out that, in an assignment of a RawByteString to another AnsiString type, the Delphi compiler should (but does not) check and eventually convert the string to the static encoding of the target. This is (almost) the only way to create strings with a different static and dynamic encoding.

+1

Show quoted text 10 lines
2) The stupid conversion to CP_ACP in an assignment *to* an RawByteString should be dropped. This applies in detail to the assignment to *function results*. 3) The function result type should be honored, in functions accepting RawByteString parameters. The Delphi compiler seems to *assume* that the results of such functions is RawByteString, so that (including beforementioned flaws) the outcome is a CP_ACP string, even if the declared function result is e.g. an UTF8String.

I offered some similar thoughts about how to define and implement such a "fully dynamically encoded" string type and how it can be implemented without harming performance, even it TStrings and siblings (and the Lazarus API) in fact use it for sake of flexibility and portability.

For Delphi compatibility this needs to be a new encoding type (say $FFFE), and provided with some appropriate name.

-Michael

Reply by email

Craig Peterson
to Michael Schnell: Any reason for this strangeness ? -Michael
> The compiler supports AnsiStrings, but these are hidden for *mobile* > targets. Any reason for this strangeness ?

They're using the mobile compiler as an opportunity to break backwards compatibility and push the language in the directions they want to go. A single, 0-based string type, automatic reference counting, no "with", etc. Apparently the developers they're chasing after are too stupid to know how to deal with more than one string type.

Craig Peterson Scooter Software

Reply by email

Jonas Maebe
to Hans-Peter Diettrich: Just an idea: What if FPC adds another encoding, similar to RawByteString ($FFFF), but…
Hans-Peter Diettrich wrote
1) In a discussion in the Embarcadero groups it turned out that, in an assignment of a RawByteString to another AnsiString type, the Delphi compiler should (but does not) check and eventually convert the string to the static encoding of the target. This is (almost) the only way to create strings with a different static and dynamic encoding. 2) The stupid conversion to CP_ACP in an assignment *to* an RawByteString should be dropped. This applies in detail to the assignment to *function results*.

The conversion does not happen for all assignments, it only happens for concatenations that are assigned to RawByteString. And even then it doesn't always happen. Please read the wiki page I wrote (trying to prevent exactly this kind of wrong statements from being further repeated, and obviously failing). I even mentioned that we will probably add a way to change the behaviour in this specific case.

Show quoted text 5 lines
3) The function result type should be honored, in functions accepting RawByteString parameters. The Delphi compiler seems to *assume* that the results of such functions is RawByteString, so that (including beforementioned flaws) the outcome is a CP_ACP string, even if the declared function result is e.g. an UTF8String. Test case: function conc(a,b: RawByteString): UTF8String; begin Result := a+b; end;

This will always return CP_UTF8 on FPC. Does it really return CP_ACP on Delphi? Even if it does, I doubt we will change that. We even couldn't easily do that, because we don't know the static code pages of the strings that are concatenated inside the RTL routine that handles this.

Then TStrings could be based on such RawByteStrings, without excess conversions or losses.

The problem with changing TStrings from AnsiString to RawByteString is not so much related to the behaviour of RawByteString, but more regarding descendent classes in existing third party (= user) source code that override methods using AnsiString parameters. We don't want to force everyone to rewrite their code so it uses RawByteString (if anything, RawByteString should probably be used as little as possible in user code, because always correctly dealing with all possible code pages is very hard).

Sorting (TStringList) eventually should ignore the dynamic encoding, i.e. work on a strictly binary (byte-by-byte) base.

Looking for just one second at the definition of the Sort methods of TStringList (and TStrings) would have prevented you from writing the above statement, which does not make any sense whatsoever (unless you want the compiler to start changing all code where a programmer passes a comparison function that does take code pages into account to the Sort methods of TStrings/TStringList).

Jonas

Reply by email

Michael Van Canneyt
to Craig Peterson: They're using the mobile compiler as an opportunity to break backwards compatibility and…
Craig Peterson wrote 9 lines
>> The compiler supports AnsiStrings, but these are hidden for *mobile* >> targets. > Any reason for this strangeness ? They're using the mobile compiler as an opportunity to break backwards compatibility and push the language in the directions they want to go. A single, 0-based string type, automatic reference counting, no "with", etc. Apparently the developers they're chasing after are too stupid to know how to deal with more than one string type.

Well, that is about 90% of all developers.

Ever talk to a PHP, Javascript or VB developer ?

You can usually start by explaining the meaning of 'bit' and 'byte', and work your way up from there.

Michael.

Reply by email

Michael Schnell
to Craig Peterson: They're using the mobile compiler as an opportunity to break backwards compatibility and…
Craig Peterson wrote 5 lines
They're using the mobile compiler as an opportunity to break backwards compatibility and push the language in the directions they want to go. A single, 0-based string type, automatic reference counting, no "with", etc. Apparently the developers they're chasing after are too stupid to know how to deal with more than one string type.

I hope fpc/Lazarus will not follow Delphi on that path.

- there have been decent discussions in multiple forums showing that that classes with "automatic reference counting" are dangerous
- castrating the Strings in that way (supposedly forcing UTF16) seems very inappropriate.

In fact I do like zero based strings. But this breaks any backwards compatibility so it can't be decently considered.

In fact I do like dropping "with" But this breaks any backwards compatibility. So I don't complain but just don't use it. (There is a decent way to implement "qualified with" blocks, but I don't think it is worth the effort.) In the end, the compiler should be smart enough to create the same code whether or nor not "with" is used.

-Michael

Reply by email

Michael Schnell
to Jonas Maebe: The conversion does not happen for all assignments, it only happens for concatenations…
Jonas Maebe wrote
but more regarding descendent classes in existing third party (= user) source code that override methods using AnsiString parameters.

Automatic type conversion should be able to handle this (as the new type would preserve and thus dynamically know the type of the information it hold).

A more sever problem with third parties is that they might derive a new class from TStrings. I did not decently check what happens to legacy code in that case. I do hope this can be automatically handled in most cases.

-Michael

Reply by email

Sven Barth
to Michael Schnell: I hope fpc/Lazarus will not follow Delphi on that path. - there have been decent…
"Michael Schnell" wrote
- there have been decent discussions in multiple forums showing that

that classes with "automatic reference counting" are dangerous

I like the idea of ARC classes. In fact I'm trying to develop an implementation that is fully backwards compatible (currently only in my head though :P )

In fact I do like zero based strings. But this breaks any backwards

compatibility so it can't be decently considered.

They can be switched on using a compiler directive (AFAIK $ZeroBasedStrings On/Off) in both current Delphi and FPC (2.7.1).

In fact I do like dropping "with" But this breaks any backwards

compatibility. So I don't complain but just don't use it. (There is a decent way to implement "qualified with" blocks, but I don't think it is worth the effort.) In the end, the compiler should be smart enough to create the same code whether or nor not "with" is used.

It would be a possibility to implement a modeswitch which switches of "with". Regarding same code: Will not be true if the the expression inside the with-header is not side effect free.

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Jonas Maebe: The conversion does not happen for all assignments, it only happens for concatenations…
Show quoted text 11 lines
On 07 Jan 2014, at 15:35, Hans-Peter Diettrich wrote: > 2) The stupid conversion to CP_ACP in an assignment *to* an > RawByteString should be dropped. This applies in detail to the > assignment to *function results*. The conversion does not happen for all assignments, it only happens for concatenations that are assigned to RawByteString. And even then it doesn't always happen. Please read the wiki page I wrote (trying to prevent exactly this kind of wrong statements from being further repeated, and obviously failing).

I've tested the behaviour, and it appears not only in assignments to RawByteStrings. See test case below.

Show quoted text 5 lines
> Test case: function conc(a,b: RawByteString): UTF8String; begin > Result := a+b; end; This will always return CP_UTF8 on FPC. Does it really return CP_ACP on Delphi? Even if it does, I doubt we will change that.

This leads me back to my previous statement: it will be simpler to do things right, than trying to achieve compatibility with *all* Delphi flaws. In detail when the Delphi flaws never have been documented...

We even couldn't easily do that, because we don't know the static code pages of the strings that are concatenated inside the RTL routine that handles this.

Right! Only the compiler can do that, and therefore the compiler should do it right.

Show quoted text 11 lines
> Then TStrings could be based on such RawByteStrings, without excess > conversions or losses. The problem with changing TStrings from AnsiString to RawByteString is not so much related to the behaviour of RawByteString, but more regarding descendent classes in existing third party (= user) source code that override methods using AnsiString parameters. We don't want to force everyone to rewrite their code so it uses RawByteString (if anything, RawByteString should probably be used as little as possible in user code, because always correctly dealing with all possible code pages is very hard).

Right <sigh>

Show quoted text 9 lines
> Sorting (TStringList) eventually should ignore the dynamic > encoding, i.e. work on a strictly binary (byte-by-byte) base. Looking for just one second at the definition of the Sort methods of TStringList (and TStrings) would have prevented you from writing the above statement, which does not make any sense whatsoever (unless you want the compiler to start changing all code where a programmer passes a comparison function that does take code pages into account to the Sort methods of TStrings/TStringList).

Fine that you took the bait ;-)

DoDi

Reply by email