> On Sep 4, 2018, at 12:35 PM, Sven Barth via fpc-pascal 
> <fpc-pascal@lists.freepascal.org> wrote:
> 
> I think you need to be clearer what you want to achieve in the end. The
> default property as intended by Maciej has the idea that it hoists the
> operators of the default property type to the record it is contained in.

Here’s my usage example which I encountered and got stuck with.

The problem is I have a base class that has some commonly used functionality 
across many subclasses but at a later time I wanted to remove the fields from 
the class to save memory. Now I’m stuck with an OOP problem where I have tons 
of syntax like obj.RegisterMethod which are used in dozens of subclasses.

The solutions currently are:

1) Put the two manager concepts into separate classes which can be subclassed. 
This may work in some instances but in others it breaks class hierarchies. If I 
want to include both I’m in trouble also because there’s no multiple 
inheritance in Pascal.

2) Put the two manager concepts into separate delegate classes which are 
included manually (delphi has the “implements” property but this doesn’t really 
do anything to help). This is more flexible but now I need to replace all calls 
as obj.methodManager.RegisterMethod which is 1) messy/long 2) introduces more 
names to remember and 3) will require lots of copy/paste. If I ever want to 
change it back I have hours of copy/pasting to do.

type
        TBaseObject = class
                private
                        methods: array of TMethod;
                        objects: array of TObject;
                public
                        { method manager }
                        procedure RegisterMethod(name: string; proc: pointer);
                        procedure InvokeMethod(name: string);
                        { object manager }
                        procedure ManageObject(obj: TObject);
        end;

// if we need either of the 2 managers we need to inherit from TBaseObject
// and take on the baggage. Typical OOP problems with deep class hierarchies.

type
        TMyObject = class (TBaseObject)
        end;
var

        obj: TMyObject;
begin
        obj := TMyObject.Create;
        obj.RegisterMethod('foo', @method);
        obj.InvokeMethod('foo');
        obj.ManageObject(otherObj);
end.

========================================================================

Using what I’ll call the “alias property” for now (using “with” is not proper 
grammar Sven mentioned, and “default” implies just one, so...) we can pull out 
the two manager concepts into separate records and include them manually into 
any class we want. Thanks to having management operators now we can get 
automatic init/finalize to manage the lifecycle but I didn’t show that here.

The alias property acts like the default property we’ve been discussing by 
calling into the fields namespace without the property name. This is the 
preferred solution for breaking up the class because once I add the manager 
record and the alias I don’t need to change any other code, everything works 
like before.

What I propose is that the default property be allowed to support multiple 
default properties. The default property already basically does this so it’s 
just a matter of performing some searches before determining which property to 
use for the given call. If we made this safe it would be a good alternative to 
subclassing and allow for some really nice delegation patterns we can’t do in 
Pascal now.

Clearly there are problems with name conflicts and precedence but surely they 
can be solved. There’s already a precedent of multiple interfaces in classes 
and redefining methods in subclasses so I don’t see why this can’t be made safe 
also. Please note the default property already introduces these problems so in 
my opinion it’s not that crazy to add more levels of search than just one.

Here’s what the class looks like broken up into delegates and using aliases so 
they calling conventions don’t change from the original.

type
        TMethodManager = record
                private
                        methods: array of TMethod;
                public
                        procedure RegisterMethod(name: string; proc: pointer);
                        procedure InvokeMethod(name: string);
        end;

type
        TObjectManager = record
                private
                        objects: array of TObject;
                public
                        procedure ManageObject(obj: TObject);
        end;

type
        TMyObjectA = class
                private
                        m_methodManager: TMethodManager;
                        property methodManager: TMethodManager alias 
m_methodManager;
        end;

type
        TMyObjectB = class
                private
                        m_objectManager: TObjectManager;
                        property objectManager: TObjectManager alias 
m_objectManager;
        end;

var
        objA: TMyObjectA;
        objB: TMyObjectB;
begin

        objA := TMyObjectA.Create;
        objA.RegisterMethod('foo', @method);
        objA.InvokeMethod('foo’);

        objB := TMyObjectB.Create;
        objB.ManageObject(otherObj);
end.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply via email to