Recent

Author Topic: Unexpected behavior of TStrings.AddStrings  (Read 3375 times)

simone

  • Hero Member
  • *****
  • Posts: 667
Unexpected behavior of TStrings.AddStrings
« on: February 27, 2022, 09:09:08 pm »
As known TStringList.AddStrings accepts an Array of String or a TStrings and adds their contents to the TStringList instance that invokes it.

Given the above, consider the following code:

Code: Pascal  [Select][+][-]
  1. program project1;
  2. uses
  3.   Classes;
  4. type
  5.   MyClass=class
  6.     private
  7.       fData : string;
  8.     public
  9.       property Data : string read fData write fData;
  10.   end;
  11. var
  12.   List : TStringList;
  13.   aClass : MyClass;
  14.  
  15. begin
  16.   List:=TStringList.Create;
  17.   aClass:=MyClass.Create;
  18.   List.Add('one');
  19.   aClass.fData:='two';
  20.   List.AddStrings(aClass.Data);
  21.   writeln(List.Text);
  22.   readln;
  23.   List.Free;
  24.   aClass.Free;
  25. end.  

In this case, using AddStrings, the content of a string property of an object is added. Nonetheless, the program works well. But is this behavior correct? I wasn't expecting that and it created a hard-to-find bug for me.

« Last Edit: February 27, 2022, 09:23:41 pm by simone »
Microsoft Windows 10/11 64 bit - Lazarus 3.8/4.0 FPC 3.2.2 x86_64-win64-win32/win64

Bart

  • Hero Member
  • *****
  • Posts: 5575
    • Bart en Mariska's Webstek
Re: Unexpected behavior of TStrings.AddStrings
« Reply #1 on: February 27, 2022, 10:33:46 pm »
It adds an array of strings with length = 1?
Bart

simone

  • Hero Member
  • *****
  • Posts: 667
Re: Unexpected behavior of TStrings.AddStrings
« Reply #2 on: February 28, 2022, 12:34:53 am »
I did not know that when a procedure / function expects an open array parameter, it is possible to invoke it with a scalar value of the same type as the array. In other words, this is possible:

Code: Pascal  [Select][+][-]
  1. program project1;
  2. var
  3.   S : string;
  4.  
  5.   procedure Proc(L : array of string);
  6.   begin
  7.     writeln(Length(L));
  8.     readln;
  9.   end;
  10.  
  11. begin
  12.   Proc(S);
  13. end.

Just for the sake of knowledge: is this behavior explicitly contemplated in the language specification?
Microsoft Windows 10/11 64 bit - Lazarus 3.8/4.0 FPC 3.2.2 x86_64-win64-win32/win64

Thaddy

  • Hero Member
  • *****
  • Posts: 17413
  • Ceterum censeo Trumpum esse delendum (Tnx Charlie)
Re: Unexpected behavior of TStrings.AddStrings
« Reply #3 on: February 28, 2022, 07:46:46 am »
Bart means List.AddStrings([aClass.Data]); Note the brackets. The parameter is an array...
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

simone

  • Hero Member
  • *****
  • Posts: 667
Re: Unexpected behavior of TStrings.AddStrings
« Reply #4 on: February 28, 2022, 08:20:23 am »
I don't use square brackets in my code.  Why does it work?
Microsoft Windows 10/11 64 bit - Lazarus 3.8/4.0 FPC 3.2.2 x86_64-win64-win32/win64

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Unexpected behavior of TStrings.AddStrings
« Reply #5 on: February 28, 2022, 08:37:29 am »
Just for the sake of knowledge: is this behavior explicitly contemplated in the language specification?
I would think that this behaviour (interpreting a string parameter as an open array of string) is a bug.
But perhaps it is an (undocumented) feature.
If the argument to the procedure is instead declared as TStringArray (i .e. a dynamic array of string) the compiler correctly points out that an ansistring is not what what was expected if that is what you feed it.
« Last Edit: February 28, 2022, 09:36:08 am by howardpc »

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1315
Re: Unexpected behavior of TStrings.AddStrings
« Reply #6 on: February 28, 2022, 09:01:18 am »
Shouldn't that be:

Code: Pascal  [Select][+][-]
  1.   aClass.Data:='two';

?

simone

  • Hero Member
  • *****
  • Posts: 667
Re: Unexpected behavior of TStrings.AddStrings
« Reply #7 on: February 28, 2022, 09:08:14 am »
Private members are visible in the same module where the class is declared. It is not strict private.
Microsoft Windows 10/11 64 bit - Lazarus 3.8/4.0 FPC 3.2.2 x86_64-win64-win32/win64

Zoran

  • Hero Member
  • *****
  • Posts: 1949
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Unexpected behavior of TStrings.AddStrings
« Reply #8 on: February 28, 2022, 09:38:30 am »
See this:
https://stackoverflow.com/questions/13490338/why-can-i-pass-a-var-of-type-x-to-a-open-array-parameter-of-that-type

There in one comment, this is quoted (but the link from there does not work for me):
Quote
    Open array arguments must be supplied with an actual array variable, a constructed array or a single variable of the argument's element type.

As far as I understand, there they say that it is not in documentation, but they found it in some bug report. There is a link to this, but it seems dead.
And google does not find this quote.
Swan, ZX Spectrum emulator https://github.com/zoran-vucenovic/swan

MarkMLl

  • Hero Member
  • *****
  • Posts: 8453
Re: Unexpected behavior of TStrings.AddStrings
« Reply #9 on: February 28, 2022, 09:52:50 am »
See this:
https://stackoverflow.com/questions/13490338/why-can-i-pass-a-var-of-type-x-to-a-open-array-parameter-of-that-type

There in one comment, this is quoted (but the link from there does not work for me):
Quote
    Open array arguments must be supplied with an actual array variable, a constructed array or a single variable of the argument's element type.

As far as I understand, there they say that it is not in documentation, but they found it in some bug report. There is a link to this, but it seems dead.
And google does not find this quote.

In any event, that's specific to Delphi. Archive.org doesn't have the page but Google currently has it cached at https://webcache.googleusercontent.com/search?q=cache:cRVV4RIWvF8J:https://docwiki.embarcadero.com/RADStudio/Sydney/en/E2192_Constants_cannot_be_used_as_open_array_arguments_(Delphi)+&cd=2&hl=en&ct=clnk&gl=uk&client=firefox-b-e

Quote
E2192 Constants cannot be used as open array arguments (Delphi)

Open array arguments must be supplied with an actual array variable, a constructed array or a single variable of the argument's element type.

Code: Pascal  [Select][+][-]
  1. program Produce;
  2.  
  3.   procedure TakesArray(s : array of String);
  4.   begin
  5.   end;
  6.  
  7.  
  8. begin TakesArray('Hello Error');
  9. end.
  10.  

The error is caused in this example because a string literal is being supplied when an array is expected. It is not possible to implicitly construct an array from a constant.

Code: Pascal  [Select][+][-]
  1. program Solve;
  2.  
  3.   procedure TakesArray(s : array of String);
  4.   begin
  5.   end;
  6.  
  7.  
  8. begin TakesArray(['Hello Error']);
  9. end.
  10.  

The solution avoids the error because the array is explicitly constructed.

If FPC doesn't document this either way the question is one for the core team. Otherwise it should IMO be treated as implementation-specific and not relied on.

MarkMLl
« Last Edit: February 28, 2022, 09:55:03 am by MarkMLl »
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

simone

  • Hero Member
  • *****
  • Posts: 667
Re: Unexpected behavior of TStrings.AddStrings
« Reply #10 on: February 28, 2022, 10:02:13 am »
The problem arises in general, not only with strings:

Code: Pascal  [Select][+][-]
  1. program project1;
  2. var
  3.   S : integer;
  4.  
  5.   procedure Proc(L : array of integer);
  6.   begin
  7.  
  8.   end;
  9.  
  10. begin
  11.   Proc(S);
  12. end.  

This means that when a procedure / function expects an open array parameter, it is possible to invoke it with a scalar value of the same type as the array.

Since Object Pascal is a strongly typed language, in my opinion this behavior is incorrect and can lead to errors that are very difficult to find.

Microsoft Windows 10/11 64 bit - Lazarus 3.8/4.0 FPC 3.2.2 x86_64-win64-win32/win64

MarkMLl

  • Hero Member
  • *****
  • Posts: 8453
Re: Unexpected behavior of TStrings.AddStrings
« Reply #11 on: February 28, 2022, 10:25:58 am »
Since Object Pascal is a strongly typed language, in my opinion this behavior is incorrect and can lead to errors that are very difficult to find.

First, you haven't said what mode you're using. Second, if Delphi does it that way then tell them they're wrong. Third, wait until one of the core team comments: either they will say that they consider it useful if not correct behaviour or that their hands are tied by Delphi's behaviour.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

jcmontherock

  • Sr. Member
  • ****
  • Posts: 300
Re: Unexpected behavior of TStrings.AddStrings
« Reply #12 on: February 28, 2022, 10:51:25 am »
It seems to me that is the same behavior of the following code:
Code: Pascal  [Select][+][-]
  1. CharArray:  Array[0..100] of Char;
  2. ....
  3. CharArray := 'abcdefghijkl';
  4.  
which works well.
Windows 11 UTF8-64 - Lazarus 4.0-64 - FPC 3.2.2

simone

  • Hero Member
  • *****
  • Posts: 667
Re: Unexpected behavior of TStrings.AddStrings
« Reply #13 on: February 28, 2022, 11:07:13 am »
Since Object Pascal is a strongly typed language, in my opinion this behavior is incorrect and can lead to errors that are very difficult to find.

First, you haven't said what mode you're using. Second, if Delphi does it that way then tell them they're wrong. Third, wait until one of the core team comments: either they will say that they consider it useful if not correct behaviour or that their hands are tied by Delphi's behaviour.

MarkMLl

The behavior occurs in both {$mode ObjFpc} and {$mode Delphi}.
Microsoft Windows 10/11 64 bit - Lazarus 3.8/4.0 FPC 3.2.2 x86_64-win64-win32/win64

MarkMLl

  • Hero Member
  • *****
  • Posts: 8453
Re: Unexpected behavior of TStrings.AddStrings
« Reply #14 on: February 28, 2022, 11:07:48 am »
It seems to me that is the same behavior of the following code:
Code: Pascal  [Select][+][-]
  1. CharArray:  Array[0..100] of Char;
  2. ....
  3. CharArray := 'abcdefghijkl';
  4.  
which works well.

No, it's not. Because in the case of your CharArray the base type is a char, while you're assigning a string.

I'm not saying that these clandestine conversions aren't convenient, but I'm beginning to feel that there are too many of them in the core language. But as been made clear in the past, it's not my decision and at least in part FPC has to toe Delphi's line.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018