Interfaces and properties - delphi

Is it possible to declare a property in an interface without declaring the get- and set-methods for it? Something like:
IValue = interface
property value: double;
end;
I want to state that the implementor should have a property called value, returning a double, but I really don't care if it returns a private field or the result from a function.
If it is possible, is it possible to declare it read/write or read-only?

No. Interfaces are implemented as function tables (basically a simple virtual method table) and the compiler needs to know there's a function to map the property onto. You can declare a property on an interface, but it has to have functions as getter/setter values, not fields. You can make it read-only or write-only, though.

When working with properties in an interface, think of the property as a shortcut to the reader/writer. Only one is required to satisfy the shortcut...otherwise it doesn't point to anything.

Related

How To: Assigning a value to a sub property of an indexed default property via "setter"

I have a class which contains the profile information of a project of mine, with loads and loads of information, its called PROFILE. To have an easy access to all the different properties of this profile I have an indexed default property. This default property(TCHANNELLIST) is a record containig again a few properties as well as another record(TCHANNELPARAMETER). The property CHANNEL is the default property (indexed) of the default property TCHANNELLIST.
Now I do have a problem when constructing the setter of these properties. (To clearify: the read function is not the problem! Please don't bother except the solution can be found in it).
The Question: How do I construct the Property/procedure/function to get the following code running
MyProfile[i][j].Name := 'Thanks_for_the_help';
Since more is more here is the structure of my records I have used. I am also willing to change the general structure if there is a better way, so I am open for suggestions.
TChannelParameter = record
// each channel gets one record for itself
public
channelType : TKanalTyp;
display_number : Integer;
Name : string;
// and a few other but you will get the idea...
end;
TChannelList = record
private
FChannelparameter_List : array of TChannelParameter ;
function GetChannelParameter(Index: Integer): TChannelParameter ;
procedure SetChannelParameter(Index: Integer); //Here I need some help
public
property Channal_GlobalNumber[index: Integer]: TChannelParameter read GetChannelParameter write SetChannelParameter; //Here I need some help
end;
To be honest I just don't have an idea (and I cant find any help online) to get that line of code running. To Read everything is not a problem but to write stuff into the "subitem" of an indexed default property is a riddle to me. Here it does not matter if I use this
A_Channel_list[i].name := 'aName';
or
MyProfile[i][j].name := 'aName';
Both setters are till now not constructed! Since I lack the basic knowledge to do so! (further I did not include the class since the handling should be the same)
If I get one running the other one should not be a problem anymore. Maybe somebody knows that this kind of operation however is not possible, please also let me know this! I will then reconstruct my class and records.
For what you are trying to achieve you don't even need Channal_GlobalNumber property to be writable. Having it readable would be enough provided that your TChannelParameter object is class type instead record type that you have now.
You see if you declare your TChannelParameter as class your Channal_GlobalNumber property will return you a reference (pointer) to that object so you can then access any of its fields/properties like if you would have variable referencing such object.
This means that you could then be changing name property/field of individual channels simply by using:
A_Channel_list[i].name := 'aName';
So why doesn't this work when your TChannelParameter is of record type. As Uwe Raabe wrote in his comment your indexed property of record type won't return you the original record from your array but instead a copy of it. Therefore making any hanges on it would not change the original record from your array but instead copy.
EDIT: Don't forget that if you change your TChannelParameter object to class type you will have to write special routines for creating such object when you are changing size of your FChannelparameter_List array as in such case this array is array of poiters to TChannelParameter classes.
Now if you want to realy avoid this and use records only you could write multiple indexed properties in TChannelList object one for each field of TChannelParameter record. So then you can use these properties getter or setter method to Access items in your array.
Unfortunately I can't write you a code example righht now since I'm not on my development computer.

Delphi - can a property read from a property?

So I just joined this forum because I could not find an answer to my simple question.
I want to declare a read-only property, and it should read from a private members read-only property. It seems like that won't work. Can I work myself around that blockade?
Here is the code snippet:
property Mine: TMineType read mMine.MineType;
Edit: Maybe I should clarify. mMine is of class TMine, which has a property MineType. MineType is of type TMineType and is read-only.
A property getter can be one of two things:
A field, or
A function.
Your code attempts to implement the getter with a property, and that does not meet the requirement stated above.
The documentation contains all the details: http://docwiki.embarcadero.com/RADStudio/en/Properties
On a practical level, you could do something like this:
function GetMineType : TMineType;
begin
result := mMine.MineType;
end;
property Mine: TMineType read GetMineType;
If you declare the GetMineType function as inline it will not generate any code.
Based on your additional information that you provided in your comments (such information should be put into the original question itself right from the start) I believe I can provide an answer which would hopefully provide solution to the problem you are facing.
In the code bellow I'm showing of how you can make parent class property accessible through descendant class by using property forwarding or property publishing.
//Base class we use
TBaseClass = class(TObject)
//Private section. Methods, fields and properties declared here are only visible from within classes declared in same unit
//but not from classes or method declared in other units.
private
FPrivateField: Integer;
function GetPrivateField: Integer;
procedure SetPrivateField(AValue: Integer);
//This property is making use of getter and setter methods in order to access FPrivateField
property PrivateFieldProperty: Integer read GetPrivateField write SetPrivateField;
//Strict private section. Methods, fields and properties declared here are only visible from descendant classes and their
//methods but not from other classes and their methods even if they are declared in the same unit.
strict private
FStrictPrivateField: Integer;
function GetStrictPrivateField: Integer;
procedure SetStrictPrivateField(AValue: Integer);
//Public section. Methods, Field and properties declared here are visible from any other class or methods regardless of
//where they are declared
public
//This property is accessing its field directly
property DirectPrivateFieldProperty: Integer read FPrivateField write FPrivateField;
//This property is making use of getter and setter methods in order to access FStrictPrivateField
property StrictPrivateFieldProperty: Integer read GetStrictPrivateField write SetStrictPrivateField;
end;
//Sub class is actually a descendant class from our base class
TSubClass = class(TBaseClass)
public
//If your parent class already has declared certain property and you want to use that property in your descendant
//class you can use so called "property forwarding" approach where you only specify the parents property name that
//you want to make available to your descendant class. This approach only allows accessing fields that are declared
//in parents class.
//If you need to access field declared in descendant class then its property must directly access that field or use
//getter and/or setter methods declared in descendant class. Such approach is called property overloading.
property DirectPrivateFieldProperty;
property PrivateFieldProperty;
//If you want to limit the access level of a descendants class property (making it read only) you need to follow standard
//property declaration guideline where you declare property type and the field to which it is accessing either directly or
//by using getter or setter methods
property ReadOnlyPrivateFieldProperty1: Integer read FPrivateField;
property ReadOnlyPrivatefieldProperty2: Integer read GetPrivateField;
//You can also declare forwarded descendant class property with different visibility of the one declared in parent class.
//Such approach is usually referred as property publishing.
property StrictPrivateFieldProperty;
end;
Note the above approaches only work when accessing properties or fields of a parent class from a descendant class but not for accessing fields or properties of other classes.
The reason for this is that property may only directly access fields of its own class or any parent classes.
Also property can only use getter and setter methods that are declared either in its own class or in any of the parent classes.
I hope this answer of mine might give you better idea about working with properties.
Now at the moment I guess properties might look a bit confusing to you but believe me when you will learn to work with them you will realize of how powerful they can actually be. I must admit that I'm still finding out new ways to use them in my projects every now and then.

Published persistent property - Should I use FMyPersistent.Assign(Value) or FMyPersistent:= Value?

When I'm building a custom component, I may implement published persistent properties. For example...
type
TMyComponent = class(TComponent)
private
FMyPersistent: TMyPersistent;
...
public
...
published
property MyPersistent: TMyPersistent read FMyPersistent write SetMyPersistent;
...
end;
Note that the procedure SetMyPersistent is not here yet, that's where the next step comes in. I right-click this object and select "Complete Class at Cursor" (or Shift + Control + C) to invoke the code completion. When it automatically creates this property setter, it automatically puts the assignment code in...
procedure TMyComponent.SetMyPersistent(const Value: TMyPersistent);
begin
FMyPersistent := Value;
end;
Now it's nice that it went ahead and completed this assignment for me. However, in normal cases, I've always grown accustomed to using...
procedure TMyComponent.SetMyPersistent(const Value: TMyPersistent);
begin
FMyPersistent.Assign(Value);
end;
In cases where the property is a type such as String or Integer, then a direct assignment is the proper way to do it. But when implementing a published property of a TPersistent, isn't it the correct method using TPersistent.Assign?
What's the essential difference between using these two assignment mechanisms? Because if using TPersistent.Assign is the appropriate thing to do, then the code completion has a slight flaw - that is, assuming that FMyPersistent := Value is considered "wrong".
Call Assign. That's why you have a property setter in the first place. If you were to directly overwrite the field, you wouldn't need a setter. Overwriting it would leak the original object you created in the constructor. You'd also notice access violations in the IDE when you modified the property in the Object Inspector.
Code completion puts the same code in every setter it creates. For properties that have additional work to do before ultimately storing the value in a field, so the field-storage statement is correct. The IDE doesn't know what you really want.
The question you should be asking yourself is - who owns the objects involved? If your component creates and owns FMyPersistent then use FMyPersistent.Assign(Value) to copy values from Value into FPersistent. If FMyPersistent merely points at an external object that someone else owns then use FMyPersistent := Value instead.

Getting an interface from GetPropValue

I want to dynamically get a property value from an object instance.
I was able to get the class properties, ordinal types and strings. The delphi source of the GetPropValue does not support tkInterface. Is there any way of getting the interface using the property info. BTW all the properties exposed are published properties.
for time being, i am using the TObject as the return type. GetPropValue returns the address of the object instance. I am typecasting that to TObject and returning the result.
If I understand you right you want to use GetInterfaceProp() function. Usage is same as GetPropValue() but it returns an IInterface which you can "cast" to right type using ie Supports().

Delphi, is possible have a property and function with the same name?

consider this code
type
TMyObject=class
private
FName: Integer;
function Name: Integer;
public
property Name : Integer read FName;
function Name(Param1 : integer) : Integer; overload;
end;
Is possible in delphi create a property and a function (or procedure) with the same name?
Exist any directive or compiler switch which allow create a class like that?
No, it is not. In addition, there is no directive or compiler switch that would allow this.
The answer is in the error message that you got when you tried this...you did try it right?
Since i see the overload keyword. I suspect that perhaps what you need default are parameters
If you use
function Name(Param1: Integer = SOME_VALUE): Integer;
it can be called as either :=Name or :=Name(5)
By accident I discovered it is possible to have a class with a property that has the same name as a function in the parent class (or vice versa).
However, I would avoid this because it will confuse you. Especially if the function and property have different meanings!
Currently, the compiler cannot do what you want.
In theory, a future version of the compiler could:
The signature of a method (overloaded or not) consists of the name and the parameter types.
The same holds for the signature of indexed properties.
Since the signature spaces of properties and methods are partially linked (hence the compiler error message), that combined space could be extended to include property overloads.
Of course that extension can backfire because of backward compatibility.
--jeroen

Resources