Sign in Join

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

Mailing lists / fpc-devel / 2011-03

(class) helper questions

20 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

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

Sven Barth

Hello together!

I'm coming along with the class helpers rather well, but I've got still a few questions. :)

1. As I'm going to implement record helpers in the next time I've noticed that I need the modeswitch for advanced records only for declaring such a record.
So how should I proceed regarding record helpers: Should the declaration of record helpers be restricted to that mode switch or should I allow it always?

2. I've done some tests regardings generics in Delphi XE and have found out, that the following example does not compile there:

=== source begin ===
   TFoo<T> = class
     Field: T;
   end;
   TFooInteger = TFoo<Integer>;

TFooHelper = class helper for TFooInteger

   end;

=== source end ===

The compiler complains here that TFoo<T> is not yet completely defined. If I introduce an alias it does not work either, but if I subclass from TFooInteger and extend that class it does work (maybe the declaration of TFooInteger is treated like an alias in Delphi?).
In FPC the above example currently compiles (there was no change needed for that). While I might file a bug report at Embarcadero, I'd like to know what your opinion regarding the correct behavior is.

3. Virtual methods and class helpers are another topic where a question is left. For correctly checking "override", etc. for helpers in mode Delphi I'm leaving the flags for virtual, etc. in the procdef although they should be ignored at the end. But the compiler checks them in some parts to do some special things for virtual methods (VMT, debug information, special code generation in the backends). The first two are solved rather easy, but should I introduce a check for helpers in the backends (calling "is_objectpascal_helper" for the owner of the procdef of the symbol) or should I introduce a "ignorevirtual" flag? I personally don't want the special virtual code to be generated for class helper methods, because it's unnecessary.

4. The syntax that was introduced by Borland is not very pascalish in my opinion. So I'd like to change the syntax for mode ObjFPC a bit (sadly this won't simplify the parser anymore because of the Delphi compatibility).

Delphi syntax:

TypeIdentifier = class|record helper(ParentHelper) for ExtendedType

Proposed FPC syntax:

TypeIdentifier = helper(ParentHelper) for class|record ExtendedType

What do you think? Maybe also the "class|record" part can be left out, because this part is not saved in the objectdef and can be determined by the compiler automatically.

Regards,
Sven

Reply by email

Paul Ishenin
to Sven Barth
Sven Barth wrote 6 lines
1. As I'm going to implement record helpers in the next time I've noticed that I need the modeswitch for advanced records only for declaring such a record. So how should I proceed regarding record helpers: Should the declaration of record helpers be restricted to that mode switch or should I allow it always?

They should be restricted as advanced records.

Show quoted text 21 lines
2. I've done some tests regardings generics in Delphi XE and have found out, that the following example does not compile there: === source begin === TFoo<T> = class Field: T; end; TFooInteger = TFoo<Integer>; TFooHelper = class helper for TFooInteger end; === source end === The compiler complains here that TFoo<T> is not yet completely defined. If I introduce an alias it does not work either, but if I subclass from TFooInteger and extend that class it does work (maybe the declaration of TFooInteger is treated like an alias in Delphi?). In FPC the above example currently compiles (there was no change needed for that). While I might file a bug report at Embarcadero, I'd like to know what your opinion regarding the correct behavior is.

I think this is a bug in XE.

Show quoted text 11 lines
3. Virtual methods and class helpers are another topic where a question is left. For correctly checking "override", etc. for helpers in mode Delphi I'm leaving the flags for virtual, etc. in the procdef although they should be ignored at the end. But the compiler checks them in some parts to do some special things for virtual methods (VMT, debug information, special code generation in the backends). The first two are solved rather easy, but should I introduce a check for helpers in the backends (calling "is_objectpascal_helper" for the owner of the procdef of the symbol) or should I introduce a "ignorevirtual" flag? I personally don't want the special virtual code to be generated for class helper methods, because it's unnecessary.

Don't generate it for class helpers using "is_objectpascal_helper".

Show quoted text 16 lines
4. The syntax that was introduced by Borland is not very pascalish in my opinion. So I'd like to change the syntax for mode ObjFPC a bit (sadly this won't simplify the parser anymore because of the Delphi compatibility). Delphi syntax: TypeIdentifier = class|record helper(ParentHelper) for ExtendedType Proposed FPC syntax: TypeIdentifier = helper(ParentHelper) for class|record ExtendedType What do you think? Maybe also the "class|record" part can be left out, because this part is not saved in the objectdef and can be determined by the compiler automatically.

I always think that if there is no need to create an incompatibility - better to not create it. But my ideas often does not get support of other FPC developers.

If you completed the class helpers syntax - then maybe to merge them into the trunk? Record helpers can be merged independently.

Best regards,
Paul Ishenin

Reply by email

Florian Klaempfl
to Paul Ishenin
Paul Ishenin wrote 19 lines
> 4. The syntax that was introduced by Borland is not very pascalish in my > opinion. So I'd like to change the syntax for mode ObjFPC a bit (sadly > this won't simplify the parser anymore because of the Delphi > compatibility). > > Delphi syntax: > > TypeIdentifier = class|record helper(ParentHelper) for ExtendedType > > Proposed FPC syntax: > > TypeIdentifier = helper(ParentHelper) for class|record ExtendedType > > What do you think? Maybe also the "class|record" part can be left out, > because this part is not saved in the objectdef and can be determined by > the compiler automatically. I always think that if there is no need to create an incompatibility - better to not create it.

For me it's one of the "implementor decides" cases :)

Reply by email

Sven Barth
to Florian Klaempfl
Florian Klaempfl wrote 22 lines
Am 09.03.2011 02:17, schrieb Paul Ishenin: >> 4. The syntax that was introduced by Borland is not very pascalish in my >> opinion. So I'd like to change the syntax for mode ObjFPC a bit (sadly >> this won't simplify the parser anymore because of the Delphi >> compatibility). >> >> Delphi syntax: >> >> TypeIdentifier = class|record helper(ParentHelper) for ExtendedType >> >> Proposed FPC syntax: >> >> TypeIdentifier = helper(ParentHelper) for class|record ExtendedType >> >> What do you think? Maybe also the "class|record" part can be left out, >> because this part is not saved in the objectdef and can be determined by >> the compiler automatically. > > I always think that if there is no need to create an incompatibility - > better to not create it. For me it's one of the "implementor decides" cases :)

Hehe *evil laughter*

Fun aside...

As you are one of the Devs who see a clean Object Pascal as a good thing to go for (I do as well), what syntax would you choose if you'd be the one to implement helper types (independant from Borland's implementation and my suggestion)?

Regards,
Sven

Reply by email

Sven Barth
to Paul Ishenin: They should be restricted as advanced records. I think this is a bug in XE. Don't…
Paul Ishenin wrote 11 lines
08.03.2011 15:24, Sven Barth wrote: > 1. As I'm going to implement record helpers in the next time I've > noticed that I need the modeswitch for advanced records only for > declaring such a record. > So how should I proceed regarding record helpers: Should the declaration > of record helpers be restricted to that mode switch or should I allow it > always? They should be restricted as advanced records.

Will do.

Show quoted text 24 lines
> 2. I've done some tests regardings generics in Delphi XE and have found > out, that the following example does not compile there: > > === source begin === > TFoo<T> = class > Field: T; > end; > > TFooInteger = TFoo<Integer>; > > TFooHelper = class helper for TFooInteger > end; > === source end === > > The compiler complains here that TFoo<T> is not yet completely defined. > If I introduce an alias it does not work either, but if I subclass from > TFooInteger and extend that class it does work (maybe the declaration of > TFooInteger is treated like an alias in Delphi?). > In FPC the above example currently compiles (there was no change needed > for that). While I might file a bug report at Embarcadero, I'd like to > know what your opinion regarding the correct behavior is. I think this is a bug in XE.

Maybe the bug is that "class helper for TFoo<Integer>" doesn't work, because the situation really looks like they treat "TFoo<Integer>" as a fully defined type and thus "TFooInteger = TFoo<Integer>" is not a declaration (like in ObjFPC "TFooInteger = specialize TFoo<Integer>"), but a simple alias.

But I'd definitely say that there's a bug involved.

Show quoted text 14 lines
> 3. Virtual methods and class helpers are another topic where a question > is left. For correctly checking "override", etc. for helpers in mode > Delphi I'm leaving the flags for virtual, etc. in the procdef although > they should be ignored at the end. But the compiler checks them in some > parts to do some special things for virtual methods (VMT, debug > information, special code generation in the backends). > The first two are solved rather easy, but should I introduce a check for > helpers in the backends (calling "is_objectpascal_helper" for the owner > of the procdef of the symbol) or should I introduce a "ignorevirtual" > flag? I personally don't want the special virtual code to be generated > for class helper methods, because it's unnecessary. Don't generate it for class helpers using "is_objectpascal_helper".

Ok, just thought I'd ask before I introduce that call in the backend.

Show quoted text 21 lines
> 4. The syntax that was introduced by Borland is not very pascalish in my > opinion. So I'd like to change the syntax for mode ObjFPC a bit (sadly > this won't simplify the parser anymore because of the Delphi > compatibility). > > Delphi syntax: > > TypeIdentifier = class|record helper(ParentHelper) for ExtendedType > > Proposed FPC syntax: > > TypeIdentifier = helper(ParentHelper) for class|record ExtendedType > > What do you think? Maybe also the "class|record" part can be left out, > because this part is not saved in the objectdef and can be determined by > the compiler automatically. I always think that if there is no need to create an incompatibility - better to not create it. But my ideas often does not get support of other FPC developers.

I personally came to the conclusion that if I can try to improve the syntax in mode ObjFPC, I'll do it. I see no need anymore to keep modes Delphi and ObjFPC completely (!) compatible as already big differences like the generics are there.

If you completed the class helpers syntax - then maybe to merge them into the trunk? Record helpers can be merged independently.

Does it matter that I already implemented some parts for preparation of record helpers?

Regards,
Sven

Reply by email

Marco van de Voort
to Sven Barth: Will do. Maybe the bug is that "class helper for TFoo<Integer>" doesn't work, because the…

In our previous episode, Sven Barth said:

I personally came to the conclusion that if I can try to improve the syntax in mode ObjFPC, I'll do it. I see no need anymore to keep modes Delphi and ObjFPC completely (!) compatible as already big differences like the generics are there.

Generics was a special case since the syntax mostly designed before Borland input arrived. And they still have to face massive uptake, and I think then the call to at least also accept Delphi syntax in objfpc mode will get stronger.

Reply by email

Florian Klaempfl
to Sven Barth: Hehe *evil laughter* Fun aside... As you are one of the Devs who see a clean Object…
Sven Barth wrote 33 lines
Am 09.03.2011 08:39, schrieb Florian Klaempfl: > Am 09.03.2011 02:17, schrieb Paul Ishenin: >>> 4. The syntax that was introduced by Borland is not very pascalish >>> in my >>> opinion. So I'd like to change the syntax for mode ObjFPC a bit (sadly >>> this won't simplify the parser anymore because of the Delphi >>> compatibility). >>> >>> Delphi syntax: >>> >>> TypeIdentifier = class|record helper(ParentHelper) for ExtendedType >>> >>> Proposed FPC syntax: >>> >>> TypeIdentifier = helper(ParentHelper) for class|record ExtendedType >>> >>> What do you think? Maybe also the "class|record" part can be left out, >>> because this part is not saved in the objectdef and can be >>> determined by >>> the compiler automatically. >> >> I always think that if there is no need to create an incompatibility - >> better to not create it. > > For me it's one of the "implementor decides" cases :) Hehe *evil laughter* Fun aside... As you are one of the Devs who see a clean Object Pascal as a good thing to go for (I do as well), what syntax would you choose if you'd be the one to implement helper types

Problem is: I never used class helpers, I even don't understand their real use, so I'am not the right person to choose :) Regardless of this, the second solution looks indeed more pascalish because it is determined as early as possible that now a class helper is following.

Reply by email

Sven Barth
to Sven Barth: Hello together! I'm coming along with the class helpers rather well, but I've got still a…

I have now reported the possible bugs I've encountered at Embarcadero's Quality Central.

In detail those are the following:

1. (strict) private nested helpers are available outside the "(strict) private" scope ( http://qc.embarcadero.com/wc/qcmain.aspx?d=92259 )
2. tchlp91.pp does not compile in Delphi while in my opinion it should ( http://qc.embarcadero.com/wc/qcmain.aspx?d=92258 )
3. "class constructors" generate an internal error and also "class destructor" compiles ( not by me:
http://qc.embarcadero.com/wc/qcmain.aspx?d=79057 )
4. "class helper for TSomeClass<SomeType>" does not work ( not by me: http://qc.embarcadero.com/wc/qcmain.aspx?d=71890 )

I'll wait a few days for the results on these issues, but as the bottom two are already open for some time I'd like to know how I should proceed regarding these (and possible also the first two, as they might take their time as well ^^ ).

The current state is the following:
1. nested helpers are not yet searched at all (I'll change that in the next time when I implement the new search algorithm)
2. the test compiles in FPC
3. "class constructor/destructor" is forbidden for helpers
4. this works in FPC

In the next days I'll work on implementing Jonas' idea regarding a hash list in tmodule. Here I'd like to know how I should proceed regarding TSymtableStack.

As I don't think it's a good idea to put the handling in TSymtableStack itself I basically have the following solutions left:
* add events that are triggered on push/pop to TSymtableStack
* make push/pop virtual methods and subclass TSymtableStack

In the first case I might need to introduce a "factory function" that creates an TSymtableStack and sets up the two events. In the second case we need to agree that all symtablestacks (maybe except the stacks for macros) must now be created as the new subclass.

Hmm... rereading what I wrote above I personally would go for the second solution.

Regards,
Sven

Reply by email

Florian Klämpfl
to Sven Barth
Sven Barth wrote
I'd like to know how I should proceed regarding these (and possible also the first two, as they might take their time as well ^^ ).

Implement things as those were fixed.

Show quoted text 12 lines
As I don't think it's a good idea to put the handling in TSymtableStack itself I basically have the following solutions left: * add events that are triggered on push/pop to TSymtableStack * make push/pop virtual methods and subclass TSymtableStack In the first case I might need to introduce a "factory function" that creates an TSymtableStack and sets up the two events. In the second case we need to agree that all symtablestacks (maybe except the stacks for macros) must now be created as the new subclass. Hmm... rereading what I wrote above I personally would go for the second solution.

I'am not a big fan of eventing in the compiler: event based designs are fine for libraries, but for the compiler typically not needed.

Reply by email

Sven Barth
to Florian Klämpfl
Florian Klämpfl wrote 7 lines
Am 13.03.2011 11:26, schrieb Sven Barth: > I'd like to know how I should proceed > regarding these (and possible also the first two, as they might take > their time as well ^^ ). Implement things as those were fixed.

Do you mean "as if those were fixed"?

Show quoted text 15 lines
> As I don't think it's a good idea to put the handling in TSymtableStack > itself I basically have the following solutions left: > * add events that are triggered on push/pop to TSymtableStack > * make push/pop virtual methods and subclass TSymtableStack > > In the first case I might need to introduce a "factory function" that > creates an TSymtableStack and sets up the two events. In the second case > we need to agree that all symtablestacks (maybe except the stacks for > macros) must now be created as the new subclass. > > Hmm... rereading what I wrote above I personally would go for the second > solution. I'am not a big fan of eventing in the compiler: event based designs are fine for libraries, but for the compiler typically not needed.

That's why I asked. So the second solution then?

Regards,
Sven

Reply by email

Florian Klämpfl
to Sven Barth
Sven Barth wrote 10 lines
Am 13.03.2011 16:40, schrieb Florian Klämpfl: > Am 13.03.2011 11:26, schrieb Sven Barth: >> I'd like to know how I should proceed >> regarding these (and possible also the first two, as they might take >> their time as well ^^ ). > > Implement things as those were fixed. > Do you mean "as if those were fixed"?

Yes.

Show quoted text 18 lines
>> As I don't think it's a good idea to put the handling in TSymtableStack >> itself I basically have the following solutions left: >> * add events that are triggered on push/pop to TSymtableStack >> * make push/pop virtual methods and subclass TSymtableStack >> >> In the first case I might need to introduce a "factory function" that >> creates an TSymtableStack and sets up the two events. In the second case >> we need to agree that all symtablestacks (maybe except the stacks for >> macros) must now be created as the new subclass. >> >> Hmm... rereading what I wrote above I personally would go for the second >> solution. > > I'am not a big fan of eventing in the compiler: event based designs are > fine for libraries, but for the compiler typically not needed. That's why I asked. So the second solution then?

IMO yes.

Reply by email

Sven Barth
to Paul Ishenin: They should be restricted as advanced records. I think this is a bug in XE. Don't…
Paul Ishenin wrote 20 lines
> 4. The syntax that was introduced by Borland is not very pascalish in my > opinion. So I'd like to change the syntax for mode ObjFPC a bit (sadly > this won't simplify the parser anymore because of the Delphi > compatibility). > > Delphi syntax: > > TypeIdentifier = class|record helper(ParentHelper) for ExtendedType > > Proposed FPC syntax: > > TypeIdentifier = helper(ParentHelper) for class|record ExtendedType > > What do you think? Maybe also the "class|record" part can be left out, > because this part is not saved in the objectdef and can be determined by > the compiler automatically. I always think that if there is no need to create an incompatibility - better to not create it. But my ideas often does not get support of other FPC developers.

I have tought about this topic a bit more. On the one hand I still want a cleaner syntax for this, but on the other hand I also understand that others want to have the ability to use "objfpc" code in Delphi with as less ifdefs as possible (or the other way round).

So what about the following compromise:
I will add my proposed syntax, but the Delphi compatible one can be activated with a mode switch (which will be enabled by default in mode Delphi).
And if you really insist very hard to have mode ObjFPC compatible with mode Delphi, I can also live with the switch meaning "enable non compatible syntax" and being disabled by default.

I plan to do something similar when RTTI attributes are implemented (either by me or someone else) as well, so the modeswitch will have its use there, too.

Regards,
Sven

Reply by email

Jonas Maebe
to Sven Barth
Sven Barth wrote
I have tought about this topic a bit more. On the one hand I still want a cleaner syntax for this, but on the other hand I also understand that others want to have the ability to use "objfpc" code in Delphi with as less ifdefs as possible (or the other way round).

It's not just that. It's also that it adds extra code to the compiler that must be maintained and that makes the parser more complicated.

JHonas

Reply by email

Paul Ishenin
to Jonas Maebe
Jonas Maebe wrote
On 14 Mar 2011, at 21:07, Sven Barth wrote: > I have tought about this topic a bit more. On the one hand I still want a cleaner syntax for this, but on the other hand I also understand that others want to have the ability to use "objfpc" code in Delphi with as less ifdefs as possible (or the other way round). It's not just that. It's also that it adds extra code to the compiler that must be maintained and that makes the parser more complicated.

+1

Also from time to time we find bugs in another proposed syntax and that other syntax becomes removed.

Best regards,
Paul Ishenin

Reply by email

Alexander Klenin
to Paul Ishenin
Paul Ishenin wrote 14 lines
15.03.2011 3:22, Jonas Maebe wrote: > > On 14 Mar 2011, at 21:07, Sven Barth wrote: > >> I have tought about this topic a bit more. On the one hand I still want a >> cleaner syntax for this, but on the other hand I also understand that others >> want to have the ability to use "objfpc" code in Delphi with as less ifdefs >> as possible (or the other way round). > > It's not just that. It's also that it adds extra code to the compiler that > must be maintained and that makes the parser more complicated. Also from time to time we find bugs in another proposed syntax and that other syntax becomes removed.

IMHO the syntax difference is so small it does not worth all the complications. However, as a compromise I can suggest inplementing it as:

TypeIdentifier = [class|record] helper(ParentHelper) for ExtendedType

i.e. make "class|record" keyword optional in objfpc mode, but do NOT allow it after "for". This way, objfpc syntax will be backwards-compatible with Delphi.

Alexander S. Klenin

Reply by email

Sven Barth
to Alexander Klenin
Alexander Klenin wrote 25 lines
On Tue, Mar 15, 2011 at 09:05, Paul Ishenin wrote: > 15.03.2011 3:22, Jonas Maebe wrote: >> >> On 14 Mar 2011, at 21:07, Sven Barth wrote: >> >>> I have tought about this topic a bit more. On the one hand I still want a >>> cleaner syntax for this, but on the other hand I also understand that others >>> want to have the ability to use "objfpc" code in Delphi with as less ifdefs >>> as possible (or the other way round). >> >> It's not just that. It's also that it adds extra code to the compiler that >> must be maintained and that makes the parser more complicated. > > Also from time to time we find bugs in another proposed syntax and that > other syntax becomes removed. IMHO the syntax difference is so small it does not worth all the complications. However, as a compromise I can suggest inplementing it as: TypeIdentifier = [class|record] helper(ParentHelper) for ExtendedType i.e. make "class|record" keyword optional in objfpc mode, but do NOT allow it after "for". This way, objfpc syntax will be backwards-compatible with Delphi.

That idea isn't that bad... (of course Jonas' point of increasing the parser's complexity still holds ^^)

Regards,
Sven

Reply by email

Jonas Maebe
to Sven Barth
Sven Barth wrote 11 lines
Am 15.03.2011 19:18, schrieb Alexander Klenin: > IMHO the syntax difference is so small it does not worth all the complications. > However, as a compromise I can suggest inplementing it as: > > TypeIdentifier = [class|record] helper(ParentHelper) for ExtendedType > > i.e. make "class|record" keyword optional in objfpc mode, but do NOT > allow it after "for". This way, objfpc syntax will be > backwards-compatible with Delphi. That idea isn't that bad... (of course Jonas' point of increasing the parser's complexity still holds ^^)

There's also another problem: I don't know whether Delphi currently does this, but in principle if both a class and a record with the same name are in scope (in case of nested types, or simply from different units), depending on whether you use "class helper" or "record helper" one or the other type could be picked by the compiler. Alternatively, it could always choose the first matched type and if it's not respectively a class or a record, the compiler could give an error.

So I think it is really best to stick to the Delphi syntax, and the Delphi syntax only.

Jonas

Reply by email

Sven Barth
to Jonas Maebe
Jonas Maebe wrote 18 lines
On 16 Mar 2011, at 09:30, Sven Barth wrote: > Am 15.03.2011 19:18, schrieb Alexander Klenin: >> IMHO the syntax difference is so small it does not worth all the complications. >> However, as a compromise I can suggest inplementing it as: >> >> TypeIdentifier = [class|record] helper(ParentHelper) for ExtendedType >> >> i.e. make "class|record" keyword optional in objfpc mode, but do NOT >> allow it after "for". This way, objfpc syntax will be >> backwards-compatible with Delphi. > > That idea isn't that bad... (of course Jonas' point of increasing the parser's complexity still holds ^^) There's also another problem: I don't know whether Delphi currently does this, but in principle if both a class and a record with the same name are in scope (in case of nested types, or simply from different units), depending on whether you use "class helper" or "record helper" one or the other type could be picked by the compiler. Alternatively, it could always choose the first matched type and if it's not respectively a class or a record, the compiler could give an error. So I think it is really best to stick to the Delphi syntax, and the Delphi syntax only.

I have already decided not to proceed with my idea, but thank you for the next point against it. :)

Regards,
Sven

Reply by email