Board index » delphi » Re: Where do concrete Attributes Belong-should have included this information before hand.

Re: Where do concrete Attributes Belong-should have included this information before hand.


2003-10-23 10:04:01 AM
delphi208
Hi Joanna,
Interesting, I never thought of registering the attributes. The Classes
yes, but did not like the idea of the user having to register every
class descended from for the business logic.
What I have done thus far is that each class descended from a
TRefelected Class can expose a list parent Classes and their attributes.
There is a TAtribute from which all attributes are descended.
Business Classes will descend from an abstract ProblemDomainObject
Class, which in turn descends from the TReflected.
I have four units so far.
TReflected and all its support Classes, including TAttribute are in the
Reflection.PAS unit. TPersistable is in the
abstractPersistanceLayerClasses.PAS have not determined what additional
classes will be in that unit yet. The AbstractBusinessLayerClasses
unit contains TProblemDomainObject and other support classes not yet
determined. There is one additional unit with contains the interfaces
for the Classes in the other units.
So now I am wondering where the Concrete Attribute classes should go.
in the Same unit as TReflected or in the same unit as the The abstract
Business Layer behaviour? Or do you think that a completely different
Unit is necessary?
Joanna Carter writes:
Quote
Cedric Pemberton writes:

| I am playing around with writing my own reflection engine (Some times
| we need to do something different to maintain our sanity), And i
| would like to know. Where you think Concrete Attributes belong in the
| Reflection Layer, or should they be placed in the business layer...

My Attribute Framework means that I register Attributes for a class with a
Type Register; this is done in the initialization section of the unit that
the class is in. An Attribute List is created in each instance of the
business class, but the Metadata is obtained from the Type Register.

Joanna

--
Joanna Carter
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker


 
 

Re: Where do concrete Attributes Belong-should have included this information before hand.

Cedric Pemberton writes:
| hello Joanna,
|
| Interesting, I never thought of registering the attributes. The
| Classes yes, but did not like the idea of the user having to register
| every class descended from for the business logic.
In my framework, every BO is also an ObjectAttribute which has a list of
Attributes to manage the metadata for the properties of that class. Because
it is impossible to get RTTI for interfaces, the Attribute Framework
provides the information necessary for persisting and displaying properties
instead.
Where at all possible, you should maintain a 'one class, one unit' approach
with some rationalisation to avoid excessively long uses clauses.
Here are some of the units and classes involved...
----------------
unit AttributeIntf;
type
IAttribute = interface
IAttributeList = interface
IAttributeIterator = interface
IBlobAttribute = interface(IAttribute)
IBooleanAttribute = interface(IAttribute)
ICharAttribute = interface(IAttribute)
IFloatAttribute = interface(IAttribute)
IInt64Attribute = interface(IAttribute)
IIntegerAttribute = interface(IAttribute)
IMemoAttribute = interface(IAttribute)
IObjectAttribute = interface(IAttribute)
IStringAttribute = interface(IAttribute)
IDateAttribute = interface(IAttribute)
ITimeAttribute = interface(IAttribute)
ITimeStampAttribute = interface(IAttribute)
IListAttribute = interface(IAttribute)
--------------------
unit AttributeImpl
TAttribute = class(TInterfacedObject, IAttribute, ...)
class function GetMetaType: TAttributeType; virtual;
private
...
protected
// IAttribute
function GetRequired: Boolean; virtual;
procedure SetRequired(Value: Boolean); virtual;
procedure Assign(const Other: IAttribute); virtual;
procedure Copy(const Other: IAttribute); virtual;
function GetAsString: string; virtual;
procedure SetAsString(const Value: string); virtual;
function GetFormatString: string; virtual;
procedure SetFormatString(const Value: string); virtual;
function GetName: string;
function GetMetadata: IMetadata; virtual;
function IsNull: Boolean; virtual;
procedure SetIsNull(Value: Boolean);
procedure SetNull; virtual;
...
public
constructor Create; overload; virtual;
constructor Create(const Name: string); overload; virtual;
constructor Create(const Other: IAttribute); overload; virtual;
destructor Destroy; override;
end;
...and implementing classes for all other attribute types in
AttributeIntf.
TObjectAttribute = class(TAttribute, IObjectAttribute)
class function GetMetaType: TAttributeType; override;
private
fAttributes: IAttributeList;
protected
function GetType: TGUID;
function GetTypeName: string; virtual; abstract;
function GetValue: IInterface; virtual;
...
function GetAttributes: IAttributeList;
procedure CreateAttributes(const IID: TGUID);
...
end;
The constructor for each business class will override
TObjectAttribute.CreateAttributes which will use the Interface Register to
create appropriate attributes for the type of the interface being
implemented.
procedure TObjectAttribute.CreateAttributes(const IID: TGUID);
begin
if GetAttributes.GetCount = 0 then
GetAttributes.AddAttributes(TInterfaceRegister.CreateAttributes(IID))
else
GetAttributes.Assign(TInterfaceRegister.CreateAttributes(IID));
end;
---------------------
unit InterfaceRegister
TInterfaceRegister = class
public
class function AddType(const IID: TGUID;
ImplementingClass: TAttributeClass;
ListImplClass: TListClass): ITypeRecord;
class function GetTypeRecord(const IID: TGUID): ITypeRecord;
class procedure AddProperty(const IID: TGUID; const Name: string;
ImplementingClass: TAttributeClass);
...
class function CreateAttributes(const IID: TGUID): IAttributeList;
class function GetMetadata(const IID: TGUID): IMetadata; overload;
class function GetMetadata(const IID: TGUID;
const PropertyName: string): IMetadata;
overload;
class function GetGUID(ImplementingClass: TAttributeClass): TGUID;
end;
-----------------------
Then I can create business classes like...
unit CustomerIntf;
type
ICustomer = interface(IObjectAttribute)
function GetCode: string;
procedure SetCode(const Value: string);
function GetName: string;
procedure SetName(const Value: string);
...
property Code: string
read GetCode
write SetCode;
property Name: string
read GetName
write SetName;
...
end;
ICustomerList = interface
ICustomerIterator = interface
---------------------
...implemented by
unit CustomerImpl
type
TCustomer = class(TPersistableObjectAttribute, ICustomer)
private
function GetCode: string;
procedure SetCode(const Value: string);
function GetName: string;
procedure SetName(const Value: string);
...
end;
TCustomerList = class
TCustomerIterator = class
The accessors for a typical property are implemented like this:
function TCustomer.GetCode: string;
begin
Result := (GetAttributes['Code'] as IStringAttribute).Value;
end;
procedure TCustomer.SetCode(const Value: string);
begin
(GetAttributes['Code'] as IStringAttribute).Value := Value;
end;
Registering of types is done in the initialization section of the
implementing class's unit.
initialization
typeRec := TInterfaceRegister.AddType(ICustomer, TCustomer,
TCustomerList);
typeRec.AddProperty('Code', TStringAttribute);
typeRec.AddProperty('Name', TStringAttribute);
...
| So now I am wondering where the Concrete Attribute classes should go.
| in the Same unit as TReflected or in the same unit as the The abstract
| Business Layer behaviour? Or do you think that a completely different
| Unit is necessary?
I still don't know what you really mean by Concrete Attributes, could you
give an example?
Joanna
 

Re: Where do concrete Attributes Belong-should have included this information before hand.

Joanna,
I am currently considering to implement my own attribute framework with
metadata for persistance and presentation. I am wondering which way to go,
because once that Delphi gets .NET-style reflection including custom
attributes (announced to be implemented in Delphi for .NET and hopefully
also integrated in Delphi for Win32 sometime later), do you see value to
implement such an attribute framework by using .NET custom attributes, or do
you think that a custom implementation such as your current implementation
will be prefereable over using the .NET custom attributes? Where do you see
pros/cons?
Regards,
-Peter
"Joanna Carter" <XXXX@XXXXX.COM>writes
Quote
Cedric Pemberton writes:

| hello Joanna,
|
| Interesting, I never thought of registering the attributes. The
| Classes yes, but did not like the idea of the user having to register
| every class descended from for the business logic.

In my framework, every BO is also an ObjectAttribute which has a list of
Attributes to manage the metadata for the properties of that class.
Because
it is impossible to get RTTI for interfaces, the Attribute Framework
provides the information necessary for persisting and displaying
properties
instead.

Where at all possible, you should maintain a 'one class, one unit'
approach
with some rationalisation to avoid excessively long uses clauses.

Here are some of the units and classes involved...
----------------
unit AttributeIntf;
type
IAttribute = interface
IAttributeList = interface
IAttributeIterator = interface
IBlobAttribute = interface(IAttribute)
IBooleanAttribute = interface(IAttribute)
ICharAttribute = interface(IAttribute)
IFloatAttribute = interface(IAttribute)
IInt64Attribute = interface(IAttribute)
IIntegerAttribute = interface(IAttribute)
IMemoAttribute = interface(IAttribute)
IObjectAttribute = interface(IAttribute)
IStringAttribute = interface(IAttribute)
IDateAttribute = interface(IAttribute)
ITimeAttribute = interface(IAttribute)
ITimeStampAttribute = interface(IAttribute)
IListAttribute = interface(IAttribute)
--------------------
unit AttributeImpl
TAttribute = class(TInterfacedObject, IAttribute, ...)
class function GetMetaType: TAttributeType; virtual;
private
...
protected
// IAttribute
function GetRequired: Boolean; virtual;
procedure SetRequired(Value: Boolean); virtual;
procedure Assign(const Other: IAttribute); virtual;
procedure Copy(const Other: IAttribute); virtual;
function GetAsString: string; virtual;
procedure SetAsString(const Value: string); virtual;
function GetFormatString: string; virtual;
procedure SetFormatString(const Value: string); virtual;
function GetName: string;
function GetMetadata: IMetadata; virtual;
function IsNull: Boolean; virtual;
procedure SetIsNull(Value: Boolean);
procedure SetNull; virtual;
...
public
constructor Create; overload; virtual;
constructor Create(const Name: string); overload; virtual;
constructor Create(const Other: IAttribute); overload; virtual;
destructor Destroy; override;
end;
...and implementing classes for all other attribute types in
AttributeIntf.

TObjectAttribute = class(TAttribute, IObjectAttribute)
class function GetMetaType: TAttributeType; override;
private
fAttributes: IAttributeList;
protected
function GetType: TGUID;
function GetTypeName: string; virtual; abstract;
function GetValue: IInterface; virtual;
...
function GetAttributes: IAttributeList;
procedure CreateAttributes(const IID: TGUID);
...
end;

The constructor for each business class will override
TObjectAttribute.CreateAttributes which will use the Interface Register to
create appropriate attributes for the type of the interface being
implemented.

procedure TObjectAttribute.CreateAttributes(const IID: TGUID);
begin
if GetAttributes.GetCount = 0 then
GetAttributes.AddAttributes(TInterfaceRegister.CreateAttributes(IID))
else
GetAttributes.Assign(TInterfaceRegister.CreateAttributes(IID));
end;
---------------------
unit InterfaceRegister
TInterfaceRegister = class
public
class function AddType(const IID: TGUID;
ImplementingClass: TAttributeClass;
ListImplClass: TListClass): ITypeRecord;
class function GetTypeRecord(const IID: TGUID): ITypeRecord;
class procedure AddProperty(const IID: TGUID; const Name: string;
ImplementingClass: TAttributeClass);
...
class function CreateAttributes(const IID: TGUID): IAttributeList;
class function GetMetadata(const IID: TGUID): IMetadata; overload;
class function GetMetadata(const IID: TGUID;
const PropertyName: string): IMetadata;
overload;
class function GetGUID(ImplementingClass: TAttributeClass): TGUID;
end;
-----------------------
Then I can create business classes like...

unit CustomerIntf;

type
ICustomer = interface(IObjectAttribute)
function GetCode: string;
procedure SetCode(const Value: string);
function GetName: string;
procedure SetName(const Value: string);
...
property Code: string
read GetCode
write SetCode;
property Name: string
read GetName
write SetName;
...
end;

ICustomerList = interface
ICustomerIterator = interface
---------------------
...implemented by

unit CustomerImpl

type
TCustomer = class(TPersistableObjectAttribute, ICustomer)
private
function GetCode: string;
procedure SetCode(const Value: string);
function GetName: string;
procedure SetName(const Value: string);
...
end;

TCustomerList = class
TCustomerIterator = class

The accessors for a typical property are implemented like this:

function TCustomer.GetCode: string;
begin
Result := (GetAttributes['Code'] as IStringAttribute).Value;
end;

procedure TCustomer.SetCode(const Value: string);
begin
(GetAttributes['Code'] as IStringAttribute).Value := Value;
end;

Registering of types is done in the initialization section of the
implementing class's unit.

initialization
typeRec := TInterfaceRegister.AddType(ICustomer, TCustomer,
TCustomerList);
typeRec.AddProperty('Code', TStringAttribute);
typeRec.AddProperty('Name', TStringAttribute);
...

| So now I am wondering where the Concrete Attribute classes should go.
| in the Same unit as TReflected or in the same unit as the The abstract
| Business Layer behaviour? Or do you think that a completely different
| Unit is necessary?

I still don't know what you really mean by Concrete Attributes, could you
give an example?

Joanna

--
Joanna Carter
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker


 

Re: Where do concrete Attributes Belong-should have included this information before hand.

Peter Sleuth writes:
| I am currently considering to implement my own attribute framework
| with metadata for persistance and presentation. I am wondering which
| way to go, because once that Delphi gets .NET-style reflection
| including custom attributes (announced to be implemented in Delphi
| for .NET and hopefully also integrated in Delphi for Win32 sometime
| later), do you see value to implement such an attribute framework by
| using .NET custom attributes, or do you think that a custom
| implementation such as your current implementation will be
| prefereable over using the .NET custom attributes? Where do you see
| pros/cons?
The only reason I developed my own attribute framework was to give me decent
metadata on interfaces.
I have two base business classes, one for transient objects and a derived
class that additionally implements IPersistable for persistent objects.
I think the idea of custom attributes is not all that different from
interfaces and I am not sure which is the best at the moment.
I am starting to port my OPF to C# and so I will get a chance to evaluate
the best way forward then.
Joanna
 

Re: Where do concrete Attributes Belong-should have included this information before hand.

Quote
I am currently considering to implement my own attribute framework with
metadata for persistance and presentation. I am wondering which way to go,
because once that Delphi gets .NET-style reflection including custom
attributes (announced to be implemented in Delphi for .NET and hopefully
also integrated in Delphi for Win32 sometime later), do you see value to
implement such an attribute framework by using .NET custom attributes, or do
you think that a custom implementation such as your current implementation
will be prefereable over using the .NET custom attributes? Where do you see
pros/cons?
The reflection support is imposed by the .NET class library, so do not
expect to see it in the Win32 version, since it would request to
redesign and change the whole class chain.
For the near future, i.e. for the lifetime of a current project your
own framework is the only choice. The .NEt version can be used as
a template to make a later switch of the implementation possible.
Regards from Germany
Franz-Leo
 

Re: Where do concrete Attributes Belong-should have included this information before hand.

comments below
"Franz-Leo Chomse" <XXXX@XXXXX.COM>writes
Quote

[snip]
Quote
The reflection support is imposed by the .NET class library, so do not
expect to see it in the Win32 version, since it would request to
redesign and change the whole class chain.
I actually thought that .NET reflection is a runtime-issue, not a
classlibrary issue, because custom attributes information is stored as
metadata in a compiled assembly, similar to resources in a Win32-executable.
If it should be a runtime-issue, than in order to implement custom
attributes in a delphi for win32-compiler, an extension of the RTL would be
required?
Quote
For the near future, i.e. for the lifetime of a current project your
own framework is the only choice. The .NEt version can be used as
a template to make a later switch of the implementation possible.
Indeed, for the near future there isnīt much choice. One could use classes
similar to the TCustomAttribute as defined in the Delphi.NET compiler
preview. Hereby one could minimize porting efforts of a current custom
attribute framework to the official .NET custom attribute framework late
once the Delphi.NET compiler is released.
The real question is - what is the best location for metadata? I currently
see three different approaches:
- external file for metadata that is then loaded at runtime (for example as
implemented in Bold)
- declaration of metadata together with a class declaration (for example as
implemented in .NET with custom attributes, another example is Instant
Objects, where metadata is also declared within a class declaration (but as
a comment, so that the delphi-compiler doesnīt get disturbed)
- instantiation of metadata in unit initialization clauses (as shown by
Joannas previous post - this might also be called "hardcoded" metadata ;-).
Personally I think that the declarative style of custom attributes as in
.NET is probably most elegant. I played a little bit with custom attributes
in the Delphi for .NET compiler preview, and liked it a lot. But maybe that
is an issue of personal preference.
Regards,
-Peter
Quote

Regards from Germany

Franz-Leo

 

Re: Where do concrete Attributes Belong-should have included this information before hand.

"Joanna Carter" <XXXX@XXXXX.COM>writes
Quote
Peter Sleuth writes:

| I am currently considering to implement my own attribute framework
| with metadata for persistance and presentation. I am wondering which
| way to go, because once that Delphi gets .NET-style reflection
| including custom attributes (announced to be implemented in Delphi
| for .NET and hopefully also integrated in Delphi for Win32 sometime
| later), do you see value to implement such an attribute framework by
| using .NET custom attributes, or do you think that a custom
| implementation such as your current implementation will be
| prefereable over using the .NET custom attributes? Where do you see
| pros/cons?

The only reason I developed my own attribute framework was to give me
decent
metadata on interfaces.

I have two base business classes, one for transient objects and a derived
class that additionally implements IPersistable for persistent objects.

I think the idea of custom attributes is not all that different from
interfaces and I am not sure which is the best at the moment.

I am starting to port my OPF to C# and so I will get a chance to evaluate
the best way forward then.
Would be nice if you could keep as informed while you proceed porting your
OPF to C#.
-Peter
Quote

Joanna

--
Joanna Carter
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker


 

Re: Where do concrete Attributes Belong-should have included this information before hand.

"Peter Sleuth" wrote
Quote

I actually thought that .NET reflection is a runtime-issue, not a
classlibrary issue, because custom attributes information is
Seems to me that Danny Thorpe opined a while back that attributes were not
inherently dependent on the .NET VM, so that implementing them in D.win32
was quite possible. Of course, whether he'll ever get the mandate to do that
is uncertain.
Quote
Personally I think that the declarative style of custom attributes
as in .NET is probably most elegant. I played a little bit with
Yes, but under 'heavy decoration' the class declaration starts getting
obscured--as classes an internal fields pick up multiple attributes you can
lose a sense of the underlying structures.
bobD
 

Re: Where do concrete Attributes Belong-should have included this information before hand.

Abstract Vs Concrete. The TAttribue Class i have is never to be
instanciated, its decendents however TIntegerAttribute would be
Concrete. ie not virtual.
Joanna Carter writes:
Quote
Cedric Pemberton writes:

| hello Joanna,
|
| Interesting, I never thought of registering the attributes. The
| Classes yes, but did not like the idea of the user having to register
| every class descended from for the business logic.

In my framework, every BO is also an ObjectAttribute which has a list of
Attributes to manage the metadata for the properties of that class. Because
it is impossible to get RTTI for interfaces, the Attribute Framework
provides the information necessary for persisting and displaying properties
instead.

Where at all possible, you should maintain a 'one class, one unit' approach
with some rationalisation to avoid excessively long uses clauses.

Here are some of the units and classes involved...
----------------
unit AttributeIntf;
type
IAttribute = interface
IAttributeList = interface
IAttributeIterator = interface
IBlobAttribute = interface(IAttribute)
IBooleanAttribute = interface(IAttribute)
ICharAttribute = interface(IAttribute)
IFloatAttribute = interface(IAttribute)
IInt64Attribute = interface(IAttribute)
IIntegerAttribute = interface(IAttribute)
IMemoAttribute = interface(IAttribute)
IObjectAttribute = interface(IAttribute)
IStringAttribute = interface(IAttribute)
IDateAttribute = interface(IAttribute)
ITimeAttribute = interface(IAttribute)
ITimeStampAttribute = interface(IAttribute)
IListAttribute = interface(IAttribute)
--------------------
unit AttributeImpl
TAttribute = class(TInterfacedObject, IAttribute, ...)
class function GetMetaType: TAttributeType; virtual;
private
....
protected
// IAttribute
function GetRequired: Boolean; virtual;
procedure SetRequired(Value: Boolean); virtual;
procedure Assign(const Other: IAttribute); virtual;
procedure Copy(const Other: IAttribute); virtual;
function GetAsString: string; virtual;
procedure SetAsString(const Value: string); virtual;
function GetFormatString: string; virtual;
procedure SetFormatString(const Value: string); virtual;
function GetName: string;
function GetMetadata: IMetadata; virtual;
function IsNull: Boolean; virtual;
procedure SetIsNull(Value: Boolean);
procedure SetNull; virtual;
....
public
constructor Create; overload; virtual;
constructor Create(const Name: string); overload; virtual;
constructor Create(const Other: IAttribute); overload; virtual;
destructor Destroy; override;
end;
...and implementing classes for all other attribute types in
AttributeIntf.

TObjectAttribute = class(TAttribute, IObjectAttribute)
class function GetMetaType: TAttributeType; override;
private
fAttributes: IAttributeList;
protected
function GetType: TGUID;
function GetTypeName: string; virtual; abstract;
function GetValue: IInterface; virtual;
....
function GetAttributes: IAttributeList;
procedure CreateAttributes(const IID: TGUID);
....
end;

The constructor for each business class will override
TObjectAttribute.CreateAttributes which will use the Interface Register to
create appropriate attributes for the type of the interface being
implemented.

procedure TObjectAttribute.CreateAttributes(const IID: TGUID);
begin
if GetAttributes.GetCount = 0 then
GetAttributes.AddAttributes(TInterfaceRegister.CreateAttributes(IID))
else
GetAttributes.Assign(TInterfaceRegister.CreateAttributes(IID));
end;
---------------------
unit InterfaceRegister
TInterfaceRegister = class
public
class function AddType(const IID: TGUID;
ImplementingClass: TAttributeClass;
ListImplClass: TListClass): ITypeRecord;
class function GetTypeRecord(const IID: TGUID): ITypeRecord;
class procedure AddProperty(const IID: TGUID; const Name: string;
ImplementingClass: TAttributeClass);
....
class function CreateAttributes(const IID: TGUID): IAttributeList;
class function GetMetadata(const IID: TGUID): IMetadata; overload;
class function GetMetadata(const IID: TGUID;
const PropertyName: string): IMetadata;
overload;
class function GetGUID(ImplementingClass: TAttributeClass): TGUID;
end;
-----------------------
Then I can create business classes like...

unit CustomerIntf;

type
ICustomer = interface(IObjectAttribute)
function GetCode: string;
procedure SetCode(const Value: string);
function GetName: string;
procedure SetName(const Value: string);
....
property Code: string
read GetCode
write SetCode;
property Name: string
read GetName
write SetName;
....
end;

ICustomerList = interface
ICustomerIterator = interface
---------------------
....implemented by

unit CustomerImpl

type
TCustomer = class(TPersistableObjectAttribute, ICustomer)
private
function GetCode: string;
procedure SetCode(const Value: string);
function GetName: string;
procedure SetName(const Value: string);
....
end;

TCustomerList = class
TCustomerIterator = class

The accessors for a typical property are implemented like this:

function TCustomer.GetCode: string;
begin
Result := (GetAttributes['Code'] as IStringAttribute).Value;
end;

procedure TCustomer.SetCode(const Value: string);
begin
(GetAttributes['Code'] as IStringAttribute).Value := Value;
end;

Registering of types is done in the initialization section of the
implementing class's unit.

initialization
typeRec := TInterfaceRegister.AddType(ICustomer, TCustomer,
TCustomerList);
typeRec.AddProperty('Code', TStringAttribute);
typeRec.AddProperty('Name', TStringAttribute);
....

| So now I am wondering where the Concrete Attribute classes should go.
| in the Same unit as TReflected or in the same unit as the The abstract
| Business Layer behaviour? Or do you think that a completely different
| Unit is necessary?

I still don't know what you really mean by Concrete Attributes, could you
give an example?

Joanna

--
Joanna Carter
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker