[fpc-devel] Status report for "class helpers"

Sven Barth pascaldragon at googlemail.com
Sun Jan 30 09:42:52 CET 2011


On 30.01.2011 09:03, Hans-Peter Diettrich wrote:
> Paul Ishenin schrieb:
>
>> For some reason the visibility is completely ignored here. I can add a
>> class helper to the strict private or even move it to another unit -
>> it is always visible.
>
> IMO class helper methods always should become visible as part of the
> class, regardless of where they are declared.
>
>  From the Delphi wiki:
>
> "You can define and associate multiple helpers with a single type.
> However, only zero or one helper applies in any specific location in
> source code. The helper defined in the nearest scope will apply. Class
> or record helper scope is determined in the normal Delphi fashion (for
> example, right to left in the unit's uses clause)."
>
> I.e. a single Helper reference (field) in the class definition is
> sufficient. This field cannot be persistent, instead it has to be
> initialized for every use case: whenever a helper is found in the
> compiled unit, or in one of its used units, it overwrites the Helper
> reference. Adding the helper elements to the class STB is not a valid
> solution, because another helper can become active at any time, during
> compilation.
>
> The ancestors of the Helper class must be searched as well.
>

Sorry, I don't understand what you want to tell here.

I personally expect a class helper that is defined inside a private 
section of a class not to be available in another unit like I can't 
access a field or another type defined in there as well.

>
> Also:
>
> "Note that the class helper function MyFunc is called, because the class
> helper takes precedence over the actual class type."
>
> That's bad, because this disallows to treat the helper like an ancestor,
> accessible in all derived classes :-(
>

If you want to have a class helper available in a derived class there is 
only one way to do this:

==== source begin ====
type
   TFoo = class
   end;

   TFooHelper = class helper for TFoo
   end; // this helper only applies to variables of type TFoo

   TBar = class(TFoo)
   end; // No methods of TFooHelper are available for variables of this type

   TBarHelper = class helper(TFooHelper) for TBar
   end; // now all methods of TFooHelper (that aren't overriden by 
TBarHelper) are available for all variables of type TBar as well
==== source end ====

> Interesting questions:
>
> 1) Unit A defines an class helper for TFoo, then uses in the
> implementation section unit B, which also defines an helper for TFoo.
> According to the above rules the helper in A should become inaccessible
> and useless then.
>

This is indeed something that I need to test. And I hope that Delphi 
behaves the way you described (because that would be the consistent 
behavior)

> 2) Similarly multiple class helpers can be defined in the implementation
> section, which are used in the immediately following code, until the
> next helper declaration.
>

Needs to be tested as well, but I hope so.

> 3) What about derived classes? Since derived classes are compiled
> independently, they never will use a reintroduced method in an class
> helper.
>

This is correct. The following does not work in Delphi:

==== source begin ====
type
   TStringsHelper = class helper for TStrings
     procedure Test;
   end;

var
   s: TStringList;
begin
   s.Test; // this won't work
   TStrings(s).Test // but this does
end;
==== source end ====

> 4) When class helpers are evaluated at compile time, according to the
> static object types (like properties are), then they could be handled
> just like the well known typecast hack:
>
> type TMyFoo = class(TFoo)
> <helper methods>
> end;
>
> with following casts of every TFoo reference into TMyFoo.
> But TFoo derived types must be handled in the same way, so that I see no
> way around an extended search inside the TFoo STB.
>

Technically class helpers ARE classes that derive from the extended 
class (here: TFoo). But there are no casts of TFoo references. When 
searching for a symbol in a class the last class helper in scope for 
that class is searched first and then the symbol is searched in the 
class itself.

> 5) What's the meaning of the "ancestor list"? IMO interfaces cannot be
> added by an class helper, and multiple inheritance is quite unlikely.
> Will the ancestor list allow to override interface *implementations*?

I don't know how you come to interfaces now. But basically from the 
outside class helpers seem to support multiple inheritance, but 
technically they don't. It works like this:

* the extended class is the real parent of the class helper class
* if the class helper has a parent ( e.g. class helper(TFooHelper) for 
TFoo ) this parent is referenced in a mostly unimportant "helperparent" 
field of tobjectdef and only used when searching for a symbol.
At the end the pseudo parent of a class helper tells the compiler to 
search the symbol table of that class helper as well.

Regards,
Sven



More information about the fpc-devel mailing list