PatV 1 Posted April 15, 2022 Delphi 11.0 Hi All, I would like to have an advice on how can I get this class more useful, I'm annoying with the 'set of ..' and the property of the set. Is there a way to change this class so I can use it with other 'set of' without recreate a similar class to resume, be able to change SOTTypeOfProperties and TTypeOfProperties so I don't need to rewrite a specific class for a different type of set Thanks Patrick SOTTypeOfProperties = Set of TTypeOfProperties; TFPropertiesCpt = class (TInterfacedObject,IFCompteurUpdate) private FItems : TDictionary<integer,rCompteurUpdate<TTypeOfProperties>>; FProperties : SOTTypeOfProperties; procedure ResetCompteurs; procedure InitList; procedure SetMax(const aValue : integer); procedure Duplicate(const aValue : TFPropertiesCpt); public constructor Create; destructor Destroy; override; property Items : TDictionary<integer,rCompteurUpdate<TTypeOfProperties>> read FItems write FItems; property Properties : SOTTypeOfProperties read FProperties; function Add(const aTypeOf : TTypeOfProperties ; const aInc : integer = 1) : TFPropertiesCpt; function WithInit : TFPropertiesCpt; function WithInfo(const aValue : TTypeOfProperties ; aProc : TProc) : TFPropertiesCpt; function WithMax(const aValue : integer) : TFPropertiesCpt; function ResetCompteur(const aValue : TTypeOfProperties) : TFPropertiesCpt; overload; procedure Execute; function AllDone : boolean; class function Clone(const aValue : TFPropertiesCpt) : TFPropertiesCpt; end; Share this post Link to post
David Heffernan 2345 Posted April 15, 2022 We can't see what the class does. You've just shown the interface. Share this post Link to post
PatV 1 Posted April 15, 2022 ok, sorry, for me it was a class ... not an interface TFPropertiesCpt = class (TInterfacedObject,IFCompteurUpdate) Share this post Link to post
Attila Kovacs 629 Posted April 15, 2022 no, you are showing the interface part of the class, not the actual class with code Share this post Link to post
PatV 1 Posted April 15, 2022 Thanks to all, I'll try to correct my post. Patrick Share this post Link to post
PeterBelow 238 Posted April 15, 2022 1 hour ago, PatV said: Delphi 11.0 Hi All, I would like to have an advice on how can I get this class more useful, I'm annoying with the 'set of ..' and the property of the set. Sets have their use but they also have limitations, e. g. they are not supported with generics as far as I know, so a "set of T" does not work. If you could replace the set with a list you could turn the class into a generic base class with the generic T: record parameter for the enumeration that the set is now defined with. Of course a check for "x in set" is much faster than a check for "x in list". The compiler (11.1) accepts something like type TWrapper<T: record> = class private FSet: TList<T>; end; TEnum = (one, two, three); TEnumWrapper = class(TWrapper<TEnum>) end; But you still cannot apply functions like Ord to T in methods of TWrapper, nor cast it to Byte. The constraint system for generics is too limited here since you cannot specify T as an ordinal type. Share this post Link to post
PatV 1 Posted April 15, 2022 Thanks a lot Peter, it was the answer I was searching for. Regards Patrick Share this post Link to post
David Heffernan 2345 Posted April 15, 2022 3 hours ago, PeterBelow said: Sets have their use but they also have limitations, e. g. they are not supported with generics as far as I know, so a "set of T" does not work. If you could replace the set with a list you could turn the class into a generic base class with the generic T: record parameter for the enumeration that the set is now defined with. Of course a check for "x in set" is much faster than a check for "x in list". The compiler (11.1) accepts something like type TWrapper<T: record> = class private FSet: TList<T>; end; TEnum = (one, two, three); TEnumWrapper = class(TWrapper<TEnum>) end; But you still cannot apply functions like Ord to T in methods of TWrapper, nor cast it to Byte. The constraint system for generics is too limited here since you cannot specify T as an ordinal type. Whilst you can't use constraints, you can use generics and RTTI to get some effective code reuse when working with enums and sets. Ideally this could be done truly generically but such is life with Delphi. Share this post Link to post
Remy Lebeau 1393 Posted April 15, 2022 (edited) 8 hours ago, PeterBelow said: Sets have their use but they also have limitations, e. g. they are not supported with generics as far as I know, so a "set of T" does not work. You can't declare a Generic for a stand-alone Set, no. But I'm pretty sure (I haven't tried it lately, though) that you can move the Set into the class, and then use a Generic on the class, eg: type TFPropertiesCpt<T> = class (TInterfacedObject, IFCompteurUpdate) public type TSetOfT = Set of T; private FItems : TDictionary<Integer, rCompteurUpdate<T>>; FProperties : TSetOfT; ... procedure Duplicate(const aValue : TFPropertiesCpt<T>); public ... property Items : TDictionary<Integer, rCompteurUpdate<T>> read FItems write FItems; property Properties : TSetOfT read FProperties; function Add(const aTypeOf: T; const aInc: Integer = 1) : TFPropertiesCpt<T>; function WithInit: TFPropertiesCpt<T>; function WithInfo(const aValue: T; aProc: TProc) : TFPropertiesCpt<T>; function WithMax(const aValue : Integer) : TFPropertiesCpt<T>; function ResetCompteur(const aValue: T): TFPropertiesCpt<T>; overload; ... class function Clone(const aValue: TFPropertiesCpt<T>): TFPropertiesCpt<T>; end; Where T can then be set to any enum type, like TTypeOfProperties, etc. Edited April 15, 2022 by Remy Lebeau Share this post Link to post
PeterBelow 238 Posted April 17, 2022 On 4/15/2022 at 9:27 PM, Remy Lebeau said: You can't declare a Generic for a stand-alone Set, no. But I'm pretty sure (I haven't tried it lately, though) that you can move the Set into the class, and then use a Generic on the class, eg: type TFPropertiesCpt<T> = class (TInterfacedObject, IFCompteurUpdate) public type TSetOfT = Set of T; private FItems : TDictionary<Integer, rCompteurUpdate<T>>; FProperties : TSetOfT; ... procedure Duplicate(const aValue : TFPropertiesCpt<T>); public ... property Items : TDictionary<Integer, rCompteurUpdate<T>> read FItems write FItems; property Properties : TSetOfT read FProperties; function Add(const aTypeOf: T; const aInc: Integer = 1) : TFPropertiesCpt<T>; function WithInit: TFPropertiesCpt<T>; function WithInfo(const aValue: T; aProc: TProc) : TFPropertiesCpt<T>; function WithMax(const aValue : Integer) : TFPropertiesCpt<T>; function ResetCompteur(const aValue: T): TFPropertiesCpt<T>; overload; ... class function Clone(const aValue: TFPropertiesCpt<T>): TFPropertiesCpt<T>; end; Where T can then be set to any enum type, like TTypeOfProperties, etc. I tried something like that and the compiler does not accept the "set of T" declaration, moaning about T not having a class or interface constraint. Which makes no sense at all in this case. Share this post Link to post
David Heffernan 2345 Posted April 17, 2022 3 hours ago, PeterBelow said: Which makes no sense at all in this case. Of course it makes sense. Try declaring set of TObject and see how that works out. You'd need to constrain to an ordinal type with 256 or fewer elements and you can't do that with constraints. Too bad we can't have templates. Share this post Link to post
Joseph MItzen 251 Posted April 18, 2022 8 hours ago, David Heffernan said: Of course it makes sense. Try declaring set of TObject and see how that works out. You'd need to constrain to an ordinal type with 256 or fewer elements and you can't do that with constraints. Too bad we can't have templates. Too bad we can't have a real set type rather than a binary array pretending to be a set type. Share this post Link to post
Fr0sT.Brutal 900 Posted April 18, 2022 The shortest form you can achieve is TClass<TEnum, TSetOfEnum>. Or have generic class working with sets of byte and only write specific converters TSetOfEnum<=>SetOfByte Share this post Link to post
PeterBelow 238 Posted April 18, 2022 On 4/17/2022 at 6:03 PM, David Heffernan said: Of course it makes sense. Try declaring set of TObject and see how that works out. You'd need to constrain to an ordinal type with 256 or fewer elements and you can't do that with constraints. Too bad we can't have templates. The error message makes no sense since it gives the impression that the code would work if T is constraint to class or interface. That is of course not the case. Share this post Link to post
Lars Fosdal 1792 Posted April 18, 2022 The lack of an Enumeration constraint is one of my big annoyances with Delphi Generics. No support for ord, pred, succ, or set of, in, or other set operators. 1 Share this post Link to post
David Heffernan 2345 Posted April 19, 2022 (edited) 18 hours ago, PeterBelow said: The error message makes no sense since it gives the impression that the code would work if T is constraint to class or interface. That is of course not the case. type TFoo<T> = class type TSetOfT = set of T; end; The compiler reports this error for me: [dcc32 Error] E2001 Ordinal type required Edited April 19, 2022 by David Heffernan Share this post Link to post
Stefan Glienke 2002 Posted April 19, 2022 On 4/18/2022 at 2:43 AM, Joseph MItzen said: Too bad we can't have a real set type Please describe the specs for a real set type. Share this post Link to post
PeterBelow 238 Posted April 19, 2022 5 hours ago, David Heffernan said: type TFoo<T> = class type TSetOfT = set of T; end; The compiler reports this error for me: [dcc32 Error] E2001 Ordinal type required My test code was a bit different and what I cited was what error insight displayed in the Structure pane; I did not try to compile it. Share this post Link to post
David Heffernan 2345 Posted April 19, 2022 2 hours ago, PeterBelow said: error insight displayed in the Structure pane; This is known to be unreliable Share this post Link to post