[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