Difference between revisions of "Helper types"

From Lazarus wiki
(first version of class helper page)
 
m (Class helpers moved to Helper types: The topic should describe both class helpers and record helpers at once (as there are only subtle differences between them))
(No difference)

Revision as of 16:51, 13 April 2011

Class helpers allow you to define new functionality for classes. This is useful if you can't extend a class because it's sealed or you can't control of which final type the class instance is (e.g. Lines/Items properties in various LCL components). This page describes class helpers in Object Pascal. For class helpers in Objective Pascal see here.

General

If you want to test this feature you need to checkout a FPC branch using the following command:

svn checkout http://svn.freepascal.org/svn/fpc/branches/svenbarth/classhelpers fpc-classhelpers

You can build the compiler like a normal trunk compiler (you should use FPC 2.4.2 for building of course).

Important:
This is a Work In Progress and thus not everything described here might work that way in the compiler or even work at all.

Syntax

The syntax for class helpers is the following: <delphi> ClassHelperName = class helper[(BaseClassHelper)] for ExtendedClass

 [properties, procedures, functions, constructors]

end [hint modifiers]; </delphi>

ClassHelperName, BaseClassHelper and ExtendedClass have to be valid Pascal identifiers, BaseClassHelper must be a class helper for a super class of ClassHelperName and ExtendedClass must be an Object Pascal class or record (the latter is not supported yet in FPC). The declarations inside a class helper are very similiar to a normal class declaration, but you must not use fields and destructors.

Usage

You can not reference class helpers anywhere in the code except when inheriting from one. The methods are always available once its unit is used and can be called as if they'd belong to the extended class.

Example: <delphi> type

 TObjectHelper = class helper for TObject
   function TheAnswer: Integer;
 end;

function TObjectHelper.TheAnswer: Integer; begin

 Result := 42;

end;

begin

 o := TObject.Create;
 o.TheAnswer;

end. </delphi>

Restrictions

A class helper may not

  • contain (class) destructors
  • contain (class) fields
  • contain abstract methods
  • "override" virtual methods of the extended class (they can be hidden by the helper though)

If a class helper has a constructor the first statement in that constructor must be a call to the parameterless constructor.

PascalDragon 21:51, 28 January 2011 (CET): This statement needs to be verified. I've found an example where this was not the case.

<delphi> type

 TObjectHelper = class helper for TObject
   constructor SomeMagicCreate(aFoo: Integer);
 end;

constructor TObjectHelper.SomeMagicCreate(aFoo: Integer); begin

 Create; // must be the first statement!

end; </delphi>

Methods of the extended class can be overloaded (in mode ObjFPC this is enabled by default, in mode Delphi you must enable this by using the overload keyword).

PascalDragon 21:51, 28 January 2011 (CET): This is not yet working in any of both modes.

<delphi> TObjectHelper = class helper for TObject

 function ToString(const aFormat: String): String; overload;

end;

function TObjectHelper.ToString(const aFormat: String): String; begin

 Result := Format(aFormat, [ToString]);

end;

var

 o: TObject;

begin

 Writeln(o.ToString('The objects name is %s'));

end. </delphi>

Inheritance

A class helper can inherit for another class helper if it extends a subclass of the class which is extend by the parent class helper.

Example: <delphi> TObjectHelper = class helper for TObject

 procedure SomeMethod;

end;

TFoo = class(TObject) end;

TFooHelper = class helper(TObjectHelper) for TFoo end; </delphi>

This allows you to use class methods that where added for a super class with a child class as well. E.g. you have a class helper that is defined for a TStrings, but you have a TStringList variable and don't want to cast to TStrings every time you want to use the helper method.

Differences between mode Delphi and ObjFPC

In mode Delphi you can use virtual, dynamic, override and message identifiers. As the concepts behind those identifiers (virtual methods, message dispatching) isn't applicable for class helpers, those keywords are ignored in mode Delphi and not allowed in mode ObjFPC. On the other hand you need to define "overload" in mode Delphi if you want to introduce a method with the same name as the original one without hiding it. In mode ObjFPC you don't need this (the same way as in normal classes).

Code examples

The following table lists some examples for class helpers found on the web and whether they work with the current implementation.

URL State
Class helper to add for ... in support for TComponent.Components / ComponentCount ok
Class helper for Delphi's TStrings: Implemented Add(Variant) ok