Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2024-01

Modifiers...

15 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin Frb

https://www.freepascal.org/docs-html/ref/refsu3.html

Is this list complete/correct?

1)
It lists bitpacked, but
    program foo; var  bitpacked: integer;  begin end; gives an error.

I thought modifiers can be used as var names?

2)
Is there, or has there once been?
(found in the synedit highlighter)
  final
  automated
  optional

3)
Not on the list, but suspected the should?
Some are on https://www.freepascal.org/docs-html/ref/refse100.html   sealed
  inline
  mwpascal
  noinline
  weakexternal
  compilerproc
  vectorcall

Reply by email

J. Gareth Moreton
to Martin Frb

Note that for 1), it should be "end.", not "end;" - make sure that isn't causing your error.

Subroutine directives like "vectorcall" I think are usable as variable names.

Kit

Martin Frb wrote 37 lines
https://www.freepascal.org/docs-html/ref/refsu3.html Is this list complete/correct? 1) It lists bitpacked, but     program foo; var  bitpacked: integer;  begin end; gives an error. I thought modifiers can be used as var names? 2) Is there, or has there once been? (found in the synedit highlighter)   final   automated   optional 3) Not on the list, but suspected the should? Some are on https://www.freepascal.org/docs-html/ref/refse100.html   sealed   inline   mwpascal   noinline   weakexternal   compilerproc   vectorcall _______________________________________________ fpc-devel maillist  -  https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply by email

Michael Van Canneyt
to Martin Frb: https://www.freepascal.org/docs-html/ref/refsu3.html Is this list complete/correct? 1) It…
Martin Frb wrote 10 lines
https://www.freepascal.org/docs-html/ref/refsu3.html Is this list complete/correct? 1) It lists bitpacked, but     program foo; var  bitpacked: integer;  begin end; gives an error. I thought modifiers can be used as var names?

Normally, yes.

Show quoted text 5 lines
2) Is there, or has there once been? (found in the synedit highlighter)   final

final comes after virtual/dynamic. Its supposed to stop you from overriding a method. Which is a bit strange because then you should not declare it virtual to begin with.

AFAIK not supported in FPC.

  automated

It is a visibility section. Delphi has/had it for win32, activeX server stuff. It's the same as public in all other aspects.

AFAIK not supported in FPC.

  optional

I have no idea what this is.

Show quoted text 12 lines
3) Not on the list, but suspected the should? Some are on https://www.freepascal.org/docs-html/ref/refse100.html   sealed   inline   mwpascal   noinline   weakexternal   compilerproc   vectorcall

I have added these to the list, thank you.

Michael.

Reply by email

Sven Barth
to Martin Frb: https://www.freepascal.org/docs-html/ref/refsu3.html Is this list complete/correct? 1) It…
Martin Frb wrote 10 lines
https://www.freepascal.org/docs-html/ref/refsu3.html Is this list complete/correct? 1) It lists bitpacked, but     program foo; var  bitpacked: integer;  begin end; gives an error. I thought modifiers can be used as var names?

"bitpacked" is not a modifier, but a keyword.

Show quoted text 5 lines
2) Is there, or has there once been? (found in the synedit highlighter)   final

As Michael wrote this can be used with methods to stop the virtual inheritance chain.

On the JVM platform it can also be used with fields which can then only be initialized inside the constructor.

automated

As Michael wrote, not supported by FPC, but by Delphi.

optional

The "optional" keyword is in the context of Objective Pascal, just like "required" is (in contrast to "requires" which is used inside "package" files).

Regards,
Sven

Reply by email

Sven Barth
to Michael Van Canneyt: Normally, yes. final comes after virtual/dynamic. Its supposed to stop you from overriding
Michael Van Canneyt wrote 12 lines
> > 2) > Is there, or has there once been? > (found in the synedit highlighter) >   final final comes after virtual/dynamic. Its supposed to stop you from overriding a method. Which is a bit strange because then you should not declare it virtual to begin with.

A person that overrides virtual methods does not always have control over whether the method had been declared as virtual. With "final" the user can tell the compiler that this method won't be overriden anymore and thus the compiler can change virtual method calls to direct method calls (assuming the compiler knows the class type involved for sure). It's similar to the WPO devirtualisation pass the compiler supports just without the need to compile the code twice.

Regards,
Sven

Reply by email

Sven Barth
to Michael Van Canneyt: Hm. That makes no sense at all to me ? You normally add override only when you know the…
Michael Van Canneyt wrote 27 lines
On Mon, 29 Jan 2024, Sven Barth via fpc-devel wrote: > Am 28.01.2024 um 12:14 schrieb Michael Van Canneyt via fpc-devel: >> >> >>> >>> 2) >>> Is there, or has there once been? >>> (found in the synedit highlighter) >>>   final >> >> final comes after virtual/dynamic. Its supposed to stop you from >> overriding >> a method. Which is a bit strange because then you should not declare it >> virtual to begin with. > > A person that overrides virtual methods does not always have control > over whether the method had been declared as virtual. Hm. That makes no sense at all to me ? You normally add override only when you know the base class has virtual. Otherwise, don't add virtual. The compiler will tell you if it was possible or not.

But that's the point: you *have* to add override. It will *always* be a virtual method ("reintroduce" doesn't count, because that's essentially the same as using a method with a completly different name). It's not in the control of the user. With "final" the user has that control.

Especially in application code (*not* library code) this can be useful, especially if the compiler generates different code in both cases (as said the compiler doesn't need to go through the VMT then if called with the real class type which can be important in performance relevant code).

Languages like C++, Java and C# all have these functionality as well and only because *you* can't think of a legitimate use for it, doesn't mean that no one can.

Regards,
Sven

Reply by email

Michael Van Canneyt
to Sven Barth: A person that overrides virtual methods does not always have control over whether the…
Sven Barth wrote 16 lines
Am 28.01.2024 um 12:14 schrieb Michael Van Canneyt via fpc-devel: > > >> >> 2) >> Is there, or has there once been? >> (found in the synedit highlighter) >>   final > > final comes after virtual/dynamic. Its supposed to stop you from > overriding > a method. Which is a bit strange because then you should not declare it > virtual to begin with. A person that overrides virtual methods does not always have control over whether the method had been declared as virtual.

Hm. That makes no sense at all to me ?

You normally add override only when you know the base class has virtual. Otherwise, don't add virtual. The compiler will tell you if it was possible or not.

Michael.

Reply by email

Michael Van Canneyt
to Sven Barth: But that's the point: you *have* to add override. It will *always* be a virtual method…
Sven Barth wrote 22 lines
>> over whether the method had been declared as virtual. > > Hm. That makes no sense at all to me ? > > You normally add override only when you know the base class has virtual. > Otherwise, don't add virtual. The compiler will tell you if it was > possible > or not. But that's the point: you *have* to add override. It will *always* be a virtual method ("reintroduce" doesn't count, because that's essentially the same as using a method with a completly different name). It's not in the control of the user. With "final" the user has that control. Especially in application code (*not* library code) this can be useful, especially if the compiler generates different code in both cases (as said the compiler doesn't need to go through the VMT then if called with the real class type which can be important in performance relevant code). Languages like C++, Java and C# all have these functionality as well and only because *you* can't think of a legitimate use for it, doesn't mean that no one can.

Please refrain from using things like '*you*' in your replies, it comes over as very agressive and authoritarian.

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.

Michael.

Reply by email

Hairy Pixels
to Sven Barth: A person that overrides virtual methods does not always have control over whether the…
On Jan 29, 2024, at 3:53 PM, Sven Barth via fpc-devel wrote: A person that overrides virtual methods does not always have control over whether the method had been declared as virtual. With "final" the user can tell the compiler that this method won't be overriden anymore and thus the compiler can change virtual method calls to direct method calls (assuming the compiler knows the class type involved for sure). It's similar to the WPO devirtualisation pass the compiler supports just without the need to compile the code twice.

I brought this up recently. Does final on classes actually do this or just final on methods? I didn't know you could even mark a method as "final" until now.

Regards,
Ryan Joseph

Reply by email

Hairy Pixels
to Michael Van Canneyt: Please refrain from using things like '*you*' in your replies, it comes over as very…
On Jan 30, 2024, at 3:56 AM, Michael Van Canneyt via fpc-devel wrote: 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.

Final means there is no possible implementation in another subclass so the compiler doesn't need to invoke the method via the vtable. Ideally this works on the class level too because it's a useful optimization.

Regards,
Ryan Joseph

Reply by email

Michael Van Canneyt
to Hairy Pixels
Hairy Pixels wrote 9 lines
> On Jan 30, 2024, at 3:56 AM, Michael Van Canneyt via fpc-devel wrote: > > 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. Final means there is no possible implementation in another subclass so the compiler doesn't need to invoke the method via the vtable. Ideally this works on the class level too because it's a useful optimization.

Yes, that is one of the effects. I understood that part.

It's probably more correct to say that you don't want there to be an override in a descendent class. Offhand I can't think of a use-case, but why not...

Michael.

Reply by email

Hairy Pixels
to Michael Van Canneyt
On Jan 30, 2024, at 8:01 PM, Michael Van Canneyt via fpc-devel wrote: It's probably more correct to say that you don't want there to be an override in a descendent class. Offhand I can't think of a use-case, but why not...

yes you do, because the descendent doesn't know the class inheriting from it is the final class in the chain or not. The compiler could figure this out if all classes were in a single unit but with compiled units there's no way to know what some other code may do.

Regards,
Ryan Joseph

Reply by email

Michael Van Canneyt
to Hairy Pixels
Hairy Pixels wrote 8 lines
> On Jan 30, 2024, at 8:01 PM, Michael Van Canneyt via fpc-devel wrote: > > It's probably more correct to say that you don't want there to be an override > in a descendent class. Offhand I can't think of a use-case, but why not... yes you do, because the descendent doesn't know the class inheriting from it is the final class in the chain or not.

'yes I do' what exactly ?

I thought I understood after your previous mail.
Now I read your sentence as an argument for not having a "final" at all, so this is again confusing for me :/

Michael.

Reply by email

Hairy Pixels
to Michael Van Canneyt
Show quoted text 5 lines
On Jan 30, 2024, at 8:53 PM, Michael Van Canneyt via fpc-devel wrote: 'yes I do' what exactly ? I thought I understood after your previous mail. Now I read your sentence as an argument for not having a "final" at all, so this is again confusing for me :/

I stepped in the middle of this and I didn't know methods could be final until now so maybe I'm confused to :). This is what we're talking out right?

type
  TAnimal = class
    procedure Fly; virtual;
  end;
  TBird = class
    procedure Fly; override;
  end;
  THawk = class
    procedure Fly; final;  // does it require override too or just final?
  end;

The idea is that now if you do:

procedure FlyHawk(hawk: THawk);
begin
  hawk.Fly;
end;

The compiler can just call THawk.Fly instead of using the VTable because it knows that no class in another unit overrode Fly after THawk. The same applies if the entire class is final too I would presume.

Regards,
Ryan Joseph

Reply by email

Sven Barth
to Michael Van Canneyt: Please refrain from using things like '*you*' in your replies, it comes over as very…
Michael Van Canneyt wrote 13 lines
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

Reply by email