Jump to content
Mike Torrettinni

Is it possible to see how compiler defines parameters?

Recommended Posts

Posted (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 by Mike Torrettinni

Share this post


Link to post
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.

  • Thanks 1

Share this post


Link to post

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
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
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
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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×