Jump to content
PatV

Reorganize a class / Set Of ..

Recommended Posts

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

ok,

 

sorry, for me it was a class ... not an interface

 

TFPropertiesCpt = class (TInterfacedObject,IFCompteurUpdate)

Share this post


Link to post
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

Thanks a lot Peter, it was the answer I was searching for.

 

Regards

 

Patrick

 

 

 

Share this post


Link to post
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
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 by Remy Lebeau

Share this post


Link to post
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
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
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

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
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

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. 

  • Like 1

Share this post


Link to post
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 by David Heffernan

Share this post


Link to post
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
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
2 hours ago, PeterBelow said:

error insight displayed in the Structure pane;

This is known to be unreliable 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×