Recent

Author Topic: Why did it compile?  (Read 507 times)

TNoob

  • New member
  • *
  • Posts: 9
Why did it compile?
« on: September 09, 2019, 08:17:22 pm »
I had a half-working form, when I realized I would have better used a TVirtualStringList instead of the simpler TTreeView. Instead of making a new form, I decided to try right-click "change class" in the form editor, because why not. Of course I did expect things to not work anymore, I rearranged my code to keep the tree data in a record, followed online instructions on how to create nodes, everything looked fine. All the while I commented out some old code and often relied on the compiler to tell me where something is wrong. I finally run it, the tree loads correctly, complete with images, but crashes when I tried to do drag-drop.  What I didn't notice at first, the drag-drop related event handlers had different parameters between the two controls, and the old ones were still in use. My bad, but why did it even compile? I would have expected the compiler to complain about the signature mismatch.
Somewhat unrelated, I also noticed that usually the empty event procedures created by the IDE have a Sender: TObject argument, but sometimes a specific control instead (TBaseVirtualTree in this case). Out of curiosity, I replaced some TObject elsewhere with the specific class of the control, and it works (plus saves me some "Sender as TWhatever"), of course as long as I only assign that procedure to controls of that same class. Here I wonder, is it ok to do this, or am I looking for trouble?

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 916
    • Burdjia
Re: Why did it compile?
« Reply #1 on: September 10, 2019, 11:01:47 am »
Without source code it is hard to tell why it compiles, but I'm pretty sure it does just because the code is correct. ::)

Take the example you comment below: Parameter Sender: TObject admits any object whose class is TObject or a descendant of TObject (in this case it is any class because all classes inherits TObject).  Then you can force any descendant class and it will compile (and in much cases will execute) without any problem.  Also note that (var AS TClass) works slightly differently than TClass (Var).  Operator AS is a bit more run-time while the other is more compliler-time.  That means that (in some cases) AS will not fail when compiling while the other does (but AS may fail at run-time).  It is explained here in the FPC manual.

Right now I don't know which class is the nearest common ascendant of TVirtualStringList and TTreeView, but I suspect it isn't too far, and even that both introduce some similar properties and methods, making them very similar to use.
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

PascalDragon

  • Hero Member
  • *****
  • Posts: 623
  • Compiler Developer
Re: Why did it compile?
« Reply #2 on: September 10, 2019, 11:45:57 am »
I had a half-working form, when I realized I would have better used a TVirtualStringList instead of the simpler TTreeView. Instead of making a new form, I decided to try right-click "change class" in the form editor, because why not. Of course I did expect things to not work anymore, I rearranged my code to keep the tree data in a record, followed online instructions on how to create nodes, everything looked fine. All the while I commented out some old code and often relied on the compiler to tell me where something is wrong. I finally run it, the tree loads correctly, complete with images, but crashes when I tried to do drag-drop.  What I didn't notice at first, the drag-drop related event handlers had different parameters between the two controls, and the old ones were still in use. My bad, but why did it even compile? I would have expected the compiler to complain about the signature mismatch.
The LFM file only contains a name of the method to use as event handler, not a signature. The correct signature for the method in your class declaration is only provided by Lazarus' code completion (which you didn't use of course, though I don't know whether Lazarus would update that anyway). The compiler has no clue about the LFM file, from it's point of view it's simply a resource file, nothing more.
So it would be a task of Lazarus to check whether the signatures still match upon a new compilation and warn accordingly.

howardpc

  • Hero Member
  • *****
  • Posts: 3149
Re: Why did it compile?
« Reply #3 on: September 10, 2019, 01:11:15 pm »
I also noticed that usually the empty event procedures created by the IDE have a Sender: TObject argument, but sometimes a specific control instead (TBaseVirtualTree in this case). Out of curiosity, I replaced some TObject elsewhere with the specific class of the control, and it works (plus saves me some "Sender as TWhatever"), of course as long as I only assign that procedure to controls of that same class. Here I wonder, is it ok to do this, or am I looking for trouble?
Checking the type of a "generic" argument is good practice, not looking for trouble.
Many standard event handlers are provided with a parameter declared as TObject -- a lowest common denominator -- which can obviously be used to pass any class at all, so covers all unknown future uses of the handler.
If your event ends up with a Sender that is not of the expected type, that almost always indicates a fundamental programmer error somewhere.

So better than using "Sender as TWhatever" which does not check the type (but merely assumes it is OK and raises an exception at runtime if not) is to do an explicit check in your event handler:
Code: Pascal  [Select]
  1. TSomeClass.TSomeMethod(Sender: TObject);
  2. begin
  3.   if not (Sender is TExpectedClass) then
  4.     Exit;
  5.  ....
  6. end;
This avoids calling invalid code, and does not present the user with an unexplained runtime exception that is not her fault.

Bart

  • Hero Member
  • *****
  • Posts: 3518
    • Bart en Mariska's Webstek
Re: Why did it compile?
« Reply #4 on: September 10, 2019, 10:38:36 pm »

PascalDragon

  • Hero Member
  • *****
  • Posts: 623
  • Compiler Developer
Re: Why did it compile?
« Reply #5 on: September 11, 2019, 09:27:53 am »
Issue 23032.
Good to know that it's already reported. :)