Mike Torrettinni 198 Posted July 29, 2022 (edited) I'm not sure how to even ask this, so let me try explain: I noticed that even if you cast variable as parameter, it works - the value is returned (I was sure casting will just pass a value): function FillStrings(aStrings: TStringList): boolean; begin aStrings.Add('a'); aStrings.Add('b'); end; ... FillStrings(TStringlist(Memo1.Lines)); This works, and this doesn't: FillStrings(Memo1.Lines); So I was trying to see if CPU debug window will show anything how the Lines were casted. Of course not. So, is it possible to see how compiler saves info about the parameters, to see what information it has on parameter when casting and when not? Edited July 29, 2022 by Mike Torrettinni Share this post Link to post
Remy Lebeau 1398 Posted July 29, 2022 41 minutes ago, Mike Torrettinni said: function FillStrings(aStrings: TStringList): boolean; begin aStrings.Add('a'); aStrings.Add('b'); end; ... FillStrings(TStringlist(Memo1.Lines)); This works It shouldn't work, though. This is just straight up undefined behavior, since the TMemo.Lines property does not point at a TStringList object, it points at a TMemoStrings object instead. And TSStringList overrides Add() whereas TMemoStrings does not, so even the vtable contents are different. Don't write code like this. The correct solution is to make FillStrings() take a TStrings instead: function FillStrings(aStrings: TStrings): boolean; begin aStrings.Add('a'); aStrings.Add('b'); end; ... FillStrings(Memo1.Lines); 41 minutes ago, Mike Torrettinni said: and this doesn't: FillStrings(Memo1.Lines); Correct, because FillStrings() expects a TStringList specifically, not a TStrings generally. 41 minutes ago, Mike Torrettinni said: So I was trying to see if CPU debug window will show anything how the Lines were casted. Of course not. Nope. 41 minutes ago, Mike Torrettinni said: So, is it possible to see how compiler saves info about the parameters, to see what information it has on parameter when casting and when not? Nope. 1 Share this post Link to post
Mike Torrettinni 198 Posted July 29, 2022 Thanks, I do have correct version as you pointed out, but this was a test if it works. casting with AS fails, but this one worked and just wanted to try to figure out why. Was testing what is good general option for lists and with TStrings works pretty well: procedure TForm1.FormCreate(Sender: TObject); var vStrings: TStringList; begin vStrings := TStringList.Create; try if FillStrings(vStrings) then Label1.Caption := vStrings.DelimitedText; finally vStrings.Free; end; FillStrings(Memo1.Lines); FillStrings(ListBox1.Items); end; Then I set a test with TStringList as parameter and of course Memo and ListBox were failing. 2 hours ago, Remy Lebeau said: vtable contents Thanks, I didn't know how this info is called. Perhaps it would be useful if IDE had optional debug window with VTM data, like CPU window. (Reading this I assume it's possible https://hallvards.blogspot.com/2006/03/hack-8-explicit-vmt-calls.html) Share this post Link to post
Lajos Juhász 293 Posted July 30, 2022 7 hours ago, Mike Torrettinni said: Thanks, I do have correct version as you pointed out, but this was a test if it works. casting with AS fails, but this one worked and just wanted to try to figure out why. As operator checks whenever your are doing a valid type conversion or not (if not exception is raised), while when writing TypeName() it will do the conversion without a check. Thus it's a valid in Delphi to write: TStringList(4).Add('Test') Now the compiler will pretend that the constant 4 is a TStringList and call the Add method on it. This is an easiest way in Delphi to have an Access Violation. (BTW. This is a reason why I started to use as instead of hard type cast recently.) Share this post Link to post
Stano 143 Posted July 30, 2022 Quote (BTW. This is a reason why I started to use as instead of hard type cast recently.) Since I'm a layman, can you give a simple example here? To know what you mean. Share this post Link to post
Lajos Juhász 293 Posted July 30, 2022 1 hour ago, Stano said: Since I'm a layman, can you give a simple example here? To know what you mean. When you've a simply example than it's trivial to see a bug. Trouble is when you change old code in hurry (critical error for what a fix must be delivered instantly) and introduce another one. For example, when you have a TStringList with objects you can cast the string instead of the object. For example, in a longer code it can be difficult to spot (you read in hurry and looks ok, you know that the object is inside the list): TMyObject(fMyStringList[lItemIndex]).DoSomething instead of: TMyObject(fMyStringList.objects[lItemIndex]).DoSomething. while this will not compile: (fMyStringList[lItemIndex] as TMyObject).DoSomething. The same goes with the original example in this thread as operator instantly shows that the cast is not valid. Disclaimer. With generics you can reduce the required typecasts however I still have to work on some D2007 code and most of the code was writen using Delphi 5. Share this post Link to post