I have been writing different classes lately, and I have noticed that I have inadvertently been reading / writing to them using both field
and property
identifiers, and I am wondering what are the pitfalls if any of doing this?
Lets use a basic class as an example:
TMyClass = class
private
FName: string;
FID: Integer;
public
constructor Create(AName: string);
destructor Destroy; override;
published
property Name: string read FName write FName;
property ID: Integer read FID write FID;
end;
By field
identifier I mean, for example FName
and FID
, and by property
identifier I mean Name
and ID
for example.
The whole purpose of the published property
is to be able to access it outside of the unit the class is written in if I am not mistaken. Which surely means the field
identifiers should be used in the unit the class is written in, after all you cannot access those field
identifiers outside the class.
This is where I have noticed that in some of the procedures (private or protected) I have not been using FName
or FID
, but instead have used the property
equivalent, Name
and ID
- or sometimes mixed.
So far I have seen no issues, and in fact I normally would use FName
and FID
but like I say, have inadvertently not done so for some reason.
Is this bad practice or could it lead to something more sinister?
Thanks.
The purpose of a property is not to allow access to class data outside of the class per se.
This could be easily done by declaring your member data as public.
The purpose of properties is to facilitate good OOP.
The following points illustrate the concept.
Side effects
The main purpose of properties is to hide the implementation details of your class and allow 'side-effects' when setting properties.
This is obvious in the VCL where changing the height
property will automatically change the window's appearance due to the side effects coded in the SetHeight Setter.
This is part of the OOP concept of information hiding.
These side effects are useful whether you are inside you class or not.
The other useful aspect kicks in when your class or one of its descendants changes the behavior of the property; adding a side-effect where there was none before.
If your old code inside the original class fiddles with the fields directly these side-effects will not trigger, breaking the change inside the descendant.
Rule of thumb: side effects
Always use the property, unless you explicitly want to prevent a side-effect from triggering. !!Remember getters can have side-effects as well.
Implementation hiding
Sometimes the fields are not a direct translation of their appearance in the property.
Or you may want to change the implementation under the hood, but keep the properties the same.
Again in this case you may want to hide these details in your own class as well, so that descendant classes do not break.
e.g. if you have your storage implemented as a red/black tree with pointers you want to minimize the impact to the rest of the routine when you decide to switch to an array based offset structure.
Rule of thumb: implementation hiding
Only access the fields directly in these routines that deal directly with the data.
Limit the number of those routines by putting general purpose routines in place, like: locaters, iterators etc.