Casting a stringlist variable to a string lazarus / 21-General ---------------------------------------------------------------------- TyneBridges · 2021-03-13 12:28 Here is some code that doesn't work (doesn't compile). logread.pas(147,69) Error: Operator is not overloaded: "AnsiString" + "TStringList" (on line 21). Obviously the reason is that DBases isn't a string, and a string is what's needed. I've tried using DBases.Name but Name isn't a property of TStringList, and @DBases doesn't work either. I don't know how to get the name of the stringlist passed to the procedure as a string, so I can show it for debugging. Gurus will probably see how to do this instantly. Can anyone help? 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 procedure FindInFolder(const Where: string; const What: string; DBases: TStringList);var  Rec: TSearchRec;  Path: string;  FResult: longint;begin  Path:= IncludeTrailingPathDelimiter(Where);  {$I-}FResult:= FindFirst(Path + '*', faAnyFile, Rec);  R:= IoResult; {$I+}  if (FResult = 0) and (R = 0) then  try    repeat      if (Rec.Attr and faDirectory) = 0 then      begin        if SameFileName(Rec.Name, What) and (Path <> LastPath) then        begin            DBases.Add(Path);            If Debugging then            begin               NStr:= FormatDateTime('DDD d MMM yyyy hh:nn:ss am/pm', Now());               {$I-}writeln(SL, NStr + '. Added list item to list ' + DBases + ' ');   Thanks. ---------------------------------------------------------------------- MarkMLl · 2021-03-13 12:41 Depending on what you want, either check that the stringlist's Count is > 0 and use the item, or use the Text property (qqv). MarkMLl ---------------------------------------------------------------------- TyneBridges · 2021-03-13 13:46 MarkMLI wrote: QuoteDepending on what you want, either check that the stringlist's Count is > 0 and use the item, or use the Text property (qqv). Thanks but I don't think either of those will work for me. I don't want the list's contents here, just to know which stringlist (my program has more than one) has been passed to the function. ---------------------------------------------------------------------- engkin · 2021-03-13 15:41 He is after the variable name, similar to asking GDB, for instance: info symbol which is kinda like the project using its own debugging information. ---------------------------------------------------------------------- bpranoto · 2021-03-13 16:16 How about inherit TStringList? 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 type  TNamedStringList = class( TStringList)  public     Name : String;  end; ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2021-03-13 19:04 Hi TyneBridges, Does this help to avoid the error? 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 writeln(SL, NStr + '. Added list item to list ' + DBases[Pred(DBases.Count)] + ' ');  Cheers, Gus ---------------------------------------------------------------------- engkin · 2021-03-13 19:46 @gcarreno, He is looking for the name of the TStringList variable that was passed as DBases when calling FindInFolder. ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2021-03-13 20:39 Hey engkin, Quote from: engkin on March 13, 2021, 08:46:09 pm@gcarreno, He is looking for the name of the TStringList variable that was passed as DBases when calling FindInFolder. DOH!! My bad!! Thanks for the heads up. If he's looking for the origin of that TStringList, he should use some other abstraction of it. A TStringList is supposed to be anonymous. Since it can be created on the fly, be part of some other component(like a TListBox) or spit out from a function/procedure. For all those reasons it doesn't have an owner or a parent, since the whole purpose of the class is to hold a list of strings. If he wants to trace the origin of that DBases, he should not pass a TStringList. He should pass the object that contains said TStringList. It makes sense to me this way, don't you think? Trying to squeeze water from the rock that is a TStringList, won't get you anywhere on the quest to find it's provenance. To be honest, in terms of the compiled program, a TStringList is just a pointer, so how you gonna get provenance from a pointer? Cheers, Gus ---------------------------------------------------------------------- engkin · 2021-03-13 21:07 It is a valid question in general, even for other types. As mentioned by others above, there are different solutions. Using debug information, it is possible to get the unit name and the line number where FindInFolder was called. Parsing that line to get the last parameter is fairly easy: 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 procedure FindInFolder(...);var  FuncName, FileName: shortstring;  LineNo: longint;  Frame: pointer;  Addr: codepointer;  ...begin  Frame := get_frame;  Addr := get_pc_addr;  get_caller_stackinfo(Frame, Addr);  GetLineInfo(ptruint(Addr), FuncName, FileName, LineNo);...end; Edit: Forgot to mention it uses unit lineinfo. And of course the application needs to be compiled with debug information. ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2021-03-13 21:19 Hi engkin, Quote from: engkin on March 13, 2021, 10:07:44 pmIt is a valid question in general, even for other types. As mentioned by others above, there are different solutions. Using debug information, it is possible to get the unit name and the line number where FindInFolder was called. See what you did there? You are searching for the Unit and Line Number of where FindInFolder() was called for. You're not trying to find out the provenance of DBases. I admit that it's a solution for TyneBridges' predicament, but it's not actually finding out where DBases came from. DBases could've been passed to the line of code you're now displaying, needing for the backtrace to go one step over, ad nauseam until TyneBridges is satisfied. But it still won't give him a nice string for him to drop on his log. Just my 2c. Cheers, Gus ---------------------------------------------------------------------- engkin · 2021-03-13 21:46 I think your understanding of his question is a little bit off. Quoting him: QuoteI don't know how to get the name of the stringlist passed to the procedure. ---------------------------------------------------------------------- Gustavo 'Gus' Carreno · 2021-03-13 23:15 Hey engkin, Quote from: engkin on March 13, 2021, 10:46:08 pmI think your understanding of his question is a little bit off. Quoting him: QuoteI don't know how to get the name of the stringlist passed to the procedure. Well, probably not. Sorry for shootin' me mouth all over the place then. Cheers, Gus ---------------------------------------------------------------------- TyneBridges · 2021-03-14 14:14 Thanks for all your contributions. As per Jamie's suggestion, I think I've got round the problem using the following two lines: 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 If DBases = CDBases then WhichList:= 'for Chrome';If DBases = EDBases then WhichList:= 'for MS Edge'; Not very elegant, but it seems to do the job. ---------------------------------------------------------------------- MarkMLl · 2021-03-14 14:23 Quote from: TyneBridges on March 14, 2021, 03:14:14 pmThanks for all your contributions. As per Jamie's suggestion, I think I've got round the problem using the following two lines: 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 If DBases = CDBases then WhichList:= 'for Chrome';If DBases = EDBases then WhichList:= 'for MS Edge'; Not very elegant, but it seems to do the job. Another approach is obviously to pass the name as a parameter together with (the pointer to) the object. MarkMLl ---------------------------------------------------------------------- TyneBridges · 2021-03-14 14:38 It raises the wider question of how to avoid spaghetti code (something I've so far failed to do utterly) when carrying out repeated operations in Pascal. I want to carry out the same sequence of operations (read a file, interpret its contents and write them in a slightly different format) on two sets of files. Since the parameters of the procedure to do this would be a string list and a text file, trying to write this elegantly has so far proved beyond me. I've had to be content with very messy code that essentially repeats a long list of operations with a few small amendments. Any thoughts on this? Do other programming languages make this any easier? (The only others I know at all are BASIC and Perl - the latter of which I don't like for its tendency to deliberate obscurity). I'm not a good programmer and I have to admit I don't understand posts 5 or 16 - that is, how I translate what's being said into my own code. ---------------------------------------------------------------------- engkin · 2021-03-14 15:16 If you don't understand post #5, which was the best solution, probably you have some reading to do. In summary, you can have new types based on existing ones, TStringList here, by customizing them to your needs, like adding a name property for instance. I give other members credit for seeing the problem in a better way than I did. ---------------------------------------------------------------------- MarkMLl · 2021-03-14 15:29 Quote from: TyneBridges on March 14, 2021, 03:38:19 pmSince the parameters of the procedure to do this would be a string list and a text file, trying to write this elegantly has so far proved beyond me. I've had to be content with very messy code that essentially repeats a long list of operations with a few small amendments. One way would be to use the same function to parse the file and return a stringlist, or nil on error. Then you have a choice of procedures to output the stringlist, before finally freeing it.. Another would be to pass the writer procedure as a parameter to the parser. The parser takes a filename as parameter, then passes a stringlist to the speficied writer before finally freeing it. QuoteAny thoughts on this? Do other programming languages make this any easier? (The only others I know at all are BASIC and Perl - the latter of which I don't like for its tendency to deliberate obscurity). I'm not a good programmer and I have to admit I don't understand posts 5 or 16 - that is, how I translate what's being said into my own code. There's not much wrong with Perl that sorting out its habitual users wouldn't fix. OK, so it's universally agreed that there are problems with things like obtuse sigil usage, but the most severe issue by far is programmers who get so deeply engrossed in the language that they are utterly convinced that any idiom, no matter how obscure, will be perfectly clear to the next person who has to maintain their work... there's a good reason why so many programmers avoid maintenance :-) MarkMLl ---------------------------------------------------------------------- Sieben · 2021-03-14 16:00 I'd second engkin's suggestion to have a closer look at OOP. I did a very brief sketch on what I think it's about in the first place here. So according to that example you would write yourself a class that would roughly look like 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 type  TFinder = class(TObject)    FWhat: string;    FWhere: string;    FDBase: TStringList;    procedure FindInFolder;  end; plus, of course, other fields or procedures you like to integrate in this class. In your app you would then create an instance of this class for each browser you want to support like eg: 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  MyEdgeFinder := TFinder.Create(...); MyChromeFinder := TFinder.Create(...); Now when you call MyEdgeFinder.FindInFolder; or MyChromeFinder.FindInFolder; the corresponding instance 'knows' on which data to operate. This is, of course, just another very rough sketch which leaves out quite a few neccesary steps like setting FWhat and FWhere and creating the TStringList inside that class. Just meant to give you an idea of what an OOP approach might look like... ---------------------------------------------------------------------- TyneBridges · 2021-03-16 13:42 Thanks to everybody for their contributions. I understand some of the theory of object orientation but have never created descendent objects and couldn't initially see how creating a TStringList descendent would help me. I see now that adding a Name field property would do what I want. I've found simple workarounds for the basic problem on the lines I mentioned above, and wouldn't have needed to do so much internal debugging if I hadn't written such sloppy code anyway, with misplaced ifs and ends... I will try to do better in future.