Am 29.01.2024 um 21:56 schrieb Michael Van Canneyt via fpc-devel:
I didn't say I cannot think of a legitimate use. I said it does not make
sense to me, as in

"I don't understand what people try to accomplish with this modifier".

Unfortunately I still don't understand after your explanation what adding 'final' is supposed to accomplish. It may well be legitimate, but I have currently no opinion as I don't understand it.

Maybe an actual code example would be more enlightening.

That way I can also add it to the docs once I understand the intended use myself.

It took me a while to find a suitable example, but now I've got one that's sounds useful.

Assume you have a class TCleanup that deals with cleaning up some stuff with a virtual (maybe abstract) method named DoCleanup:

=== code begin ===

type
  TCleanup = class
  public
    procedure DoCleanup; virtual;
  end;

=== code end ===

Now assume there's a child class that does some very specific stuff in its DoCleanup method that relies on the order and where a user may only customize it a specific part:

=== code begin ===

type
  TWhateverCleanup = class
  private
    procedure Step1;
    procedure Step2;
    procedure Step3;
  protected
    procedure DoCustomCleanup; virtual;
  public
    procedure DoCleanup; override;
  end;

procedure TWhateverCleanup.DoCleanup;
begin
  Step1;
  Step2;
  DoCustomCleanup;
  Step3;
end;

=== code end ===

Now as the class is now someone that inherits from TWhateverCleanup might override DoCleanup, but adding something in front of or after the DoCleanup call would be wrong.

The ability to declare the method DoCleanup as final makes it clear to someone who inherits from the class, that no, you should not modify that, use a different way (in this case DoCustomCleanup) to customize its behavior.

And when I came upon this example I noticed that we use a similar scheme inside the compiler:

The tdef and tsym descendants have a virtual ppuwrite method. These classes have platform specific implementations so that e.g. the m68k tparavarsym descendant can write the register location for the syscall calling convention to the PPU. However due to how the writing to a PPU is implemented it's a bad idea to override the platform independant ppuwrite method, call inherited and then write the custom stuff. This had already led to problems in the past. Thus Jonas had introduced a new virtual ppuwrite_platform method that is supposed to be implemented by the platform specific descendants and made the platform independant ppuwrite implementations in the specific tdef and tsym implementations final so that no one that inherits from the tdef/tsym descendants gets the idea to mess inside that method again.

I've learned - during my research - that this is called "safe design".

Regards,
Sven
_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to