Unexpected behavior of TStrings.AddStrings lazarus / 31-LCL ---------------------------------------------------------------------- simone · 2022-02-27 20:09 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;uses  Classes;type  MyClass=class    private      fData : string;    public      property Data : string read fData write fData;  end;var  List : TStringList;  aClass : MyClass; begin  List:=TStringList.Create;  aClass:=MyClass.Create;  List.Add('one');  aClass.fData:='two';  List.AddStrings(aClass.Data);  writeln(List.Text);  readln;  List.Free;  aClass.Free;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. ---------------------------------------------------------------------- Bart · 2022-02-27 21:33 It adds an array of strings with length = 1? Bart ---------------------------------------------------------------------- simone · 2022-02-27 23:34 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;var  S : string;   procedure Proc(L : array of string);  begin    writeln(Length(L));    readln;  end; begin  Proc(S);end. Just for the sake of knowledge: is this behavior explicitly contemplated in the language specification? ---------------------------------------------------------------------- Thaddy · 2022-02-28 06:46 Bart means List.AddStrings([aClass.Data]); Note the brackets. The parameter is an array... ---------------------------------------------------------------------- simone · 2022-02-28 07:20 I don't use square brackets in my code.  Why does it work? ---------------------------------------------------------------------- howardpc · 2022-02-28 07:37 Quote from: simone on February 28, 2022, 12:34:53 amJust 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. ---------------------------------------------------------------------- SymbolicFrank · 2022-02-28 08:01 Shouldn't that be: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   aClass.Data:='two'; ? ---------------------------------------------------------------------- simone · 2022-02-28 08:08 Private members are visible in the same module where the class is declared. It is not strict private. ---------------------------------------------------------------------- Zoran · 2022-02-28 08:38 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. ---------------------------------------------------------------------- MarkMLl · 2022-02-28 08:52 Quote from: Zoran on February 28, 2022, 09:38:30 amSee 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.googleuser content.com/search?q=cache:cRVV4RIWvF8J:https://docwiki.embarcadero.co m/RADStudio/Sydney/en/E2192_Constants_cannot_be_used_as_open_array_arg uments_(Delphi)+&cd=2&hl=en&ct=clnk&gl=uk&client=firefox-b-e QuoteE2192 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program Produce;   procedure TakesArray(s : array of String);  begin  end;  begin TakesArray('Hello Error');end.  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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program Solve;   procedure TakesArray(s : array of String);  begin  end;  begin TakesArray(['Hello Error']);end.  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 ---------------------------------------------------------------------- simone · 2022-02-28 09:02 The problem arises in general, not only with strings: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;var  S : integer;   procedure Proc(L : array of integer);  begin   end; begin  Proc(S);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. ---------------------------------------------------------------------- MarkMLl · 2022-02-28 09:25 Quote from: simone on February 28, 2022, 10:02:13 amSince 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 ---------------------------------------------------------------------- jcmontherock · 2022-02-28 09:51 It seems to me that is the same behavior of the following code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i CharArray:  Array[0..100] of Char;....CharArray := 'abcdefghijkl'; which works well. ---------------------------------------------------------------------- simone · 2022-02-28 10:07 Quote from: MarkMLl on February 28, 2022, 10:25:58 amQuote from: simone on February 28, 2022, 10:02:13 amSince 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}. ---------------------------------------------------------------------- MarkMLl · 2022-02-28 10:07 Quote from: jcmontherock on February 28, 2022, 10:51:25 amIt seems to me that is the same behavior of the following code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i CharArray:  Array[0..100] of Char;....CharArray := 'abcdefghijkl'; 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 ---------------------------------------------------------------------- Thaddy · 2022-02-28 10:31 Quote from: howardpc on February 28, 2022, 08:37:29 amI would think that this behaviour (interpreting a string parameter as an open array of string) is a bug. Of course not: AddStrings indicates an array, even if the array has just one member. So the solution is sheer logical. So if you would use AddStrings instead of add , an array of string is the correct syntax.[] For single strings you can just use plain add. ---------------------------------------------------------------------- simone · 2022-02-28 11:16 AddStrings expects an Array of Strings or a TStringList. So it shouldn't accept a string. A string is not (formally) equivalent to an array of strings with length =1. In the example I posted, a string that is not in square brackets is passed to AddStrings. ---------------------------------------------------------------------- PascalDragon · 2022-02-28 13:43 Quote from: simone on February 28, 2022, 12:34:53 amI 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program project1;var  S : string;   procedure Proc(L : array of string);  begin    writeln(Length(L));    readln;  end; begin  Proc(S);end. Just for the sake of knowledge: is this behavior explicitly contemplated in the language specification? While not documented as such, yes, this is explicitly supported. So please file a bug for the documentation of open array parameters that this is missing. Side note: this functionality works with essentially no effort, because an open array parameter is internally a pointer to the first element of the array plus an additional parameter with the High value. A single element then is simply a pointer to that element and the High parameter has a value of 1. This also explains the error in Delphi that (untyped) constants can't be used: one can't get a pointer to them. ---------------------------------------------------------------------- MarkMLl · 2022-02-28 14:13 Quote from: PascalDragon on February 28, 2022, 02:43:37 pmWhile not documented as such, yes, this is explicitly supported. So please file a bug for the documentation of open array parameters that this is missing. Thanks for the clarification. MarkMLl ---------------------------------------------------------------------- simone · 2022-02-28 14:40 @PascalDragon: Thanks for the in-depth explanations. I imagined that this equivalence was allowed by the internal representation of data structures. This behavior can certainly be convenient in many cases. In my case it caused me some problems during a refactoring process, in which at some point I changed a data structure from array of string to string. The compiler did not complain in front of a procedure that expected a parameter of type array of string and instead was now receiving a string. For this reason it took me a long time to understand that this implicit conversion was the cause of some malfunctions in the software.