Can we say :
type
TPerson = class
private
pName : string;
public
property Name : string read pName write pName;
end;
Is equal with :
type
TPerson = class
private
pName : string;
public
procedure SetName(val: string);
function GetName:String;
end;
//{... implementing SetName And GetName...}
??
Please explain to me where we need to use "property" and where not. Tnx
It's all about the design of the class. Technically, 'everything' you can do with properties, you can do without them, but the code will not be as elegant. Good design also makes the classes easier to use, and reduces the risk of making mistakes.
First, your comparing
TPerson = class
private
FName: string;
public
property Name: string read FName write FName;
end;
to
TPerson = class
private
FName: string;
public
procedure SetName(const Name: string);
function GetName: string;
end;
isn't quite fair. Indeed, in the first case, you have no chance of doing something when the value is set (or read). So a more appropriate comparison would be to compare the latter code to
TPerson = class
private
FName: string;
procedure SetName(const Name: string);
function GetName: string;
public
property Name: string read GetName write SetName;
end;
For instance, if you write a control, you often need to invalidate (basically, repaint) the control when you alter a property, say, the 'Sweater colour' of the TPerson. For instance,
TPerson = class
private
FSweaterColor: string;
procedure SetSweaterColor(const Value: TColor);
public
property SweaterColor: TColor read FSweaterColor write SetSweaterColor;
end;
...
implementation
procedure TPerson.SetSweaterColor(const Value: TColor);
begin
if FSweaterColor <> Value then
begin
FSweaterColor := Value;
Invalidate; // causes a repaint of the control
end;
end;
Anyhow, what's the point of properties? Well, the point, basically, is to make a nice interface of the class: It should be easy to use for someone not interested in the details of its implementation. By using properties, you can achieve this goal. Indeed, to read the current colour of the sweater, you just read Anna.SweaterColor, and to set it, you just Anna.SweaterColor := clRed. You don't know if this simply sets a variable or causes a procedure to run, and you don't care. As far as you are concerned, a TPerson object simply has a readable and setable property called SweaterColor.
You can also create properties that are read-only (no write) or write-only (no read). But no matter how you implement the read and write (if at all) of a property, the property will look the same from the class user's point of view. He need not remember to use SetSweaterColor or GetSweaterColor (in fact, they are private and not accessible to him), but only the SweaterColor property.
This also hints at another benefit of using properties. Public and published properties are visible to the users of the class, while the private members are not (like the field FSweaterColor and the SetSweaterColor procedure). This is good. Because now you know that the only way for the class user to change the sweater colour of a person is to use the SweaterColor property, which guaranteed will repaint the control. If the FSweaterColor variable were public, the user of the class might set this and wonder, "why doesn't anything happen when I change the sweater color?" Of course, you don't need properties to get this benefit: a private FSweaterColor field and public GetSweaterColor and SetSweaterColor would do just as well, but then you'd need to write a GetSweaterColor function even though no processing is required to get the color. Also, the user of the class need to learn to use two identifiers instead of one.
More concretely, if you use the Delphi IDE to program, you will see that the published property (-y+ies) will show up in the Object Inspector, where you are allowed to read/change them (if applicable). How would that be possible if it weren't for properties?
All this being said, sometimes you don't use properties even though you could. For instance, if you have a read-only 'property', you might go for a single public GetSomething function instead of a read-only property. After all, that would save you some coding. Similarly, if you have a write-only property, you could go with a single public SetSomething procedure, which will also save you code. Finally, if you have a read/write property that requires no processing either way (neither to get nor to set), you could simply use a public variable!
So, after all, you need to decide on a good design of your class on a class-by-class basis. I guess the short version of my overly long answer is similar to David's comment:
Use whichever you prefer, whichever is more convenient.
Properties is a nice piece of syntactic sugar. They are equivalent to a pair of getEnabled and setEnabled Methods, but most programmers (and programming languages) prefer properties instead. For example there are less entries in the code-completion window.
Furthermore they separate "variable like" stuff (so the data, the object is supposed to work with) from the methods that work with the data.
Properties are not limited to components, they are very useful otherwise. You can define a public interface with a property and implement some validation logic afterwards. (Not possible with a public field) But you nee only two lines of code for a simple property, compared to 8 lines for the methods.
More important for the object inspector is the published keyword, only published properties are displayed in the OI.
No. These two codes are NOT equal.
We use property when we implement the TPerson class as a component, customizable in Delphi's Object Inspector. Take a look at the TButton class, for example. All the things you can alter in the Object Inspector (Caption, Width, Name, etc.) are marked in the source code with the property keyword.
If you create a class that will be used in your program but not as a component, you don't use the property keyword.
Related
I'm trying to find out if there is a way to do things similar to Delphi's enhanced RTTI features.
As far as I know FPC doesn't provide RTTI features which appeared in Delphi since Delphi 2010. But I'd like to find some way to do a few tricks during runtime.
Using typinfo unit in FPC I can do such things as:
get Object published property list - via getPropList from typinfo unit;
get/set value of the Object's published property - via GetPropValue(...): Variant/SetPropValue(...Value: Variant);
get published method - via MethodAddres;
But I haven't found a way to do things like:
call methods;
call constructors, or create Objects;
Update: the problem with constructors is much like methods one - I want to have a way to pass different params in it:
// concept of code
type
TClass = class of TObject;
TMyClass1 = class
public
constructor Create(Param1: Integer; Param2: string); override;
end;
TMyClass2 = class
public
constructor Create(ObjectParam: Object); override;
end;
TParams = array of Variant;
var
Classes: array of TClass
Instances: array of Object;
ParamArray: array of TParams;
...
For I := 0 to Count-1 do
begin
LocalConstructor := #(Classes[I].Create);
Instances[I] := CallConstructor(LocalConstructor, ParamArray[I]);
end;
So I need to call constructor without knowing its signature.
So my problem is to call an Object's method and pass some parameters to it. It could look like function CallMethod(Instance: Object; MethodName: String; Params: array of Variant): Variant;
If I'm not mistaken it could be solved via Delphi's 2010+ RTTI. But before using enhanced Delphi's RTTI I'd like to understand is it possible in FPC.
In other words my current problem is pass arguments to a routine.
I know it can be done using this scheme:
type
TmyProc = procedure CallMe(x: byte);
...
var proc: TmyProc;
...
proc := pointerToFunc^;
proc(0);
But I need to implement it without knowing count and types of parameters (during compile time).
There are a few links related to the topic:
Delphi: Call a function whose name is stored in a string
http://www.swissdelphicenter.ch/torry/showcode.php?id=1745
The second article (http://www.swissdelphicenter.ch/torry/showcode.php?id=1745) describes a way to pass arguments to a routine imported from DLL by name. Which is almost that I need I suppose. But I'm not sure that way is reliable.
Maybe there's any library, which implements these things using "old" typinfo unit (without RTTI unit)?
Also I'm interested in a way to create some kind of universal event handlers - procedures which can be assigned to different events (with different sets of parameters) e.g.:
procedure myEventHandler(params: array of variant);
...
Button.OnClick := myEventHandler;
Button.OnMouseMove := myEventHandler;
is this possible? Or at least something similar to it?
You can call methods, even not published, using MethodAddress, but it's up to you to ensure correct argument list.
You can call constructors using metaclasses (class references), example of it could be seen in TCollection: you pass class of your collection item at runtime and then it can be created when needed. By defining abstract class with virtual (and probably abstract) constructor, you can come up with argument list you wish, some example here.
AFAIK there is no way to determine argument list at runtime, but if you design both the methods to call and caller itself, there are many ways you can implement similar behavior.
For example, you pass variant open array (Array of const), as it's done in Format(), so number of arguments and its type may vary. But even having one and only pointer as the argument, you sure can pass as many as you want, all you need to do is to come up with some class to which it will lead.
I would like to use attributes to read/write in property values to/from the registry.
All of the examples I have looked use a Load/Save function to loop over all the properties and examine the attributes. Instead of having a Load/Save routine I would like to read the value from the registry when the property is read or written. However, I can't figure out how to find out the name of the current property in the Read method.
I know I could have a one line getter/setter for my properties that pass in the correct string values to the Read/Write methods. I was hoping I could use attributes. Then when I define simple classes with the properties I want to save and restore. I would not need to write have any code for those classes. Everything would be dealt with the in the base class.
It could be that this is not possible.
I'm taking this example from Robert Love as my starting point:
http://robstechcorner.blogspot.de/2009/10/ini-persistence-rtti-way.html
type
RegValueAttribute = class(TCustomAttribute)
private
FName: string;
FDefaultValue: string;
published
constructor Create(const aName : string;const aDefaultValue : String = '');
property Name : string read FName write FName;
property DefaultValue : string read FDefaultValue write FDefaultValue;
end;
TRegBaseClass = class
protected
procedure WriteString(AValue: string);
function ReadString: string;
end;
TMyRegClass = class(TRegBaseClass)
public
[RegValueAttribute('MySavedProperty', 'DefaultValue')]
property MySavedProperty: string read ReadString write WriteString;
end;
///////////////////////////////////////////
function TRegBaseClass.ReadString: string;
begin
// ?? Is there any way to get the attributes for the property
// that got me here.
end;
procedure TRegBaseClass.ReadString(AValue: string);
begin
// ?? Is there any way to get the attributes for the property
// that got me here.
end;
A given getter/setter can be used for multiple properties. The only way for a getter/setter to know which property is the caller is to use the index specifier on the property declaration, which then gets passed to the getter/setter as an input parameter. The getter/setter can then use RTTI to loop through the owning object's properties looking for the property with the specified index, and then use the attributes of that property as needed.
The relationship is that the the property has associated with it a getter and a setter. The getter/setter itself has no a priori knowledge that it is being used as a getter/setter. For instance, multiple properties could use the same getter/setter.
So the best you can do, as it stands, is to iterate over all the properties of the type, using RTTI, looking for the currently executing method as a property getter/setter. That does not sound like much fun.
I suspect that the best attribute based approach involves attaching attributes to the getter/setter methods.
I've added a class variables to the base class of a deep class hierarchy. It's an integer intended to count number of instances created per class type. But I've run into a problem.
Given the example:
TBaseClass = class
private
class var fCreated: integer;
public
class function NewInstance: TObject; override;
end;
TDescendant = class(TBaseClass)
end;
...
class function TBaseClass.NewInstance: TObject;
begin
result := inherited NewInstance;
inc(fCreated);
end;
I assumed that I can use the class var to store the number of instances created per class, but this does not seem to be the case.
Inspecting TBaseClass.fCreated returns same value as TDescendant.fCreated, changing one via inspector changes the other, so it behaves as if fCreated is a single global var.
I expected fCreated to be maintained per class type, isn't that the point ? What am I missing ?
You are missing nothing. Your analysis of how class variables work is correct. A class var is nothing more than a global variable that is scoped by the class.
One simple solution for you is to use a dictionary to count the instances. A more hacky approach is to use a trick of mine that Hallvard Vassbotn blogged about, which (ab)uses the VMT to store class-specific fields. You can read all about it here.
You see TDescendant.fCreated as the same as TBaseClass.fCreated, becuse they are in the same unit, and therefore TDesendant sees the TBaseClass private fields. If you put them into separeted units, this will be over. Of if you declare fCreated not as Prvate, but Strict Private, TDescendant won't see it.
What are pros and cons of duplication an object instance with constructor or instance function?
Example A:
type
TMyObject = class
strict private
FField: integer;
public
constructor Create(srcObj: TMyObject); overload;
//alternatively:
//constructor CreateFrom(srcObj: TMyObject);
property Field: integer read FField;
end;
constructor TMyObject.Create(srcObj: TMyObject);
begin
inherited Create;
FField := srcObj.Field;
end;
Example B:
type
TMyObject = class
strict private
FField: integer;
public
function Clone: TMyObject;
property Field: integer read FField;
end;
function TMyObject.Clone: TMyObject;
begin
Result := TMyObject.Create;
Result.FField := FField;
end;
One major difference immediately springs to mind - in the latter case the Create constructor would have to be virtual so that a class hierarchy supporting Clone could be built basing on the TMyObject.
Assume that this is not a problem - that TMyObject and everything based on it is entirely under my control. What is your preferred way of doing copy constructor in Delphi? Which version do you find more readable? When would you use former or latter approach? Discuss. :)
EDIT:
My main concern with the first example is that the usage is very heavy compared to the second approach, i.e.
newObj := TMyObject.Create(oldObj)
vs.
newObj := oldObj.Clone;
EDIT2 or "Why I want single-line operation"
I agree that Assign is a reasonable approach in most cases. It's even reasonable to implement 'copy constructor' internally by simply using assign.
I'm usually creating such copies when multithreading and passing objects through the message queue. If object creation is fast, I usually pass a copy of the original object because that really simplifies the issues of object ownership.
IOW, I prefer to write
Send(TMyObject.Create(obj));
or
Send(obj.Clone);
to
newObj := TMyObject.Create;
newObj.Assign(obj);
Send(newObj);
The first adds information about which object to want to create, the second not. This can be used to instantiate e.g. a descendant or an ancestor of a class
The Delphi way (TPersistent) separates creation and cloning:
dest := TSomeClass.Create;
dest.Assign(source);
and has this same property that you explicitly choose the class to instantiate. But you don't need two constructors, one for normal use, and one where you want to clone.
edit due to oneline requirement
You can mix it of course using Delphi metaclasses (untested)
type
TBaseSomeObject = class;
TBaseObjectClass = class of TBaseSomeObject;
TBaseSomeObject = class(TPersistent)
function Clone(t: TBaseObjectClass = nil): TBaseSomeObject; virtual;
end;
...
function TBaseSomeObject.Clone(t: TBaseObjectClass = nil): TBaseSomeObject;
begin
if Assigned(t) then
Result := t.Create
else
Result := TBaseObjectClass(Self.ClassType).Create;
Result.Assign(Self);
end;
SendObject(obj.Clone); // full clone.
SendObject(obj.Clone(TDescandantObject)); // Cloned into Descendant object
For the rest, just implement your assign() operators, and you can mix multiple ways.
edit2
I replaced the code above with code tested in D2009. There are some dependencies of the types that might have confused you, hope it is clearer this way. Of course you'll have to study the assign mechanism. I also tested the metaclass=nil default parameter and it works, so I added it.
I don't think there is a correct way it just depend on personal style. (And as Marco pointed out, there are more ways.)
The constructor way is short but it violates the principle that the constructor must only construct the object. Which is possibly not a problem.
The clone way is short although you need to provide a call for each class.
The assign way is more Delphi like. It separates creation and initialization which is good because we like the one method one function concept that makes code better to maintain.
And if you implement Assign using streams, you have only one place to worry about which fields need to be available.
I like the clone style - but only in Java (or any other GC language). I used it some times in Delphi, but mostly I stay with Create and Assign, because it is much clearer who is responsible for the destruction of the object.
I use the second method, the one with the Clone function, and it works like a charm, even with complex classes. I find it more readable and error proof.
I have designed a hierarchy, every class has 2 readonly properties mapped to 2 private fields.
Every class has a cosntructor that inherits the parent class one.
The problem is that at every level of hierarchy the number of parameters increase of 2:
TBaseClass.Create (par1, par2);
TSubClass.Create(par1, par2, par3, par4);
TSubSubClass.Create(par1, par2, par3, par4, par5, par6);
[...]
Is it ok to have constructors with 6-8 parameteres? After creation my objects should be immutable, so this is why I try to initialize all fileds in the constructors.
Is there another technique you can suggest or should I go with the above mentioned approach? Thanks.
As long as they're well-documented, I've never had any stigma against functions with large numbers of parameters. So an 8-param constructor wouldn't scare me.
However, I can see where the explosion-of-params could occur here, especially if you start adding more than 2 properties per object. I could also see an uncomfortable proliferation of constructor overloads, if some of those params can be defaulted/optional.
With that in mind, you might want to encapsulate the complexities of setting all those params, by using a construction pattern. Builder comes to mind, though Factory or Prototype might also be useful.
Best to stick with conventions when you can. A Builder implies a sequential or multiple object creation process. Abstract Factory is more appropriate for creating a single object from a hierarchy.
Having said that, the regularity does seem a little odd. Does SubClass3 in fact need all 6 properties or only it's two? Remember LSP - SubClass3 is supposed to be completely substitutible for BaseClass so at each level the new ancestor assumes responsibility for the entire set, which is usually more than just passing them back through constructors.
Why don't you let those properties be writable and protect the object by casting it to an interface? Like this:
type
IMyObject = interface
function GetProperty1(): integer;
function GetProperty2(): boolean;
end;
TMyObject = class(TInterfacedObject, IMyObject)
public
constructor Create();
function GetProperty1(): integer;
function GetProperty2(): boolean;
procedure SetProperty1(Value: integer);
procedure SetProperty2(Value: boolean);
end;
function CreateMyObject: IMyObject;
var obj: TMyObject
begin
obj := TMyObject.Create;
obj.SetProperty1(45);
obj.SetProperty2(false);
Result := obj;
end;