Search code examples
delphidelphi-xe

Is there a easier way to define a Enum type based on a boolean value?


Overview

Not entirely sure if the question is worded appropriately or not, but I previously asked this question which relates to this one: How do I correctly implement a Set in a class as a property?

I like to keep code as short, minimal and readible as possible, and this is where I think some code could be written better but I am running into problems.


An example first of 2 ways to read the value in a Set:

The long way:

if (Delphi1 in IDECompatibility) then
  CheckListBox1.Checked[0] := True;
if (Delphi2 in IDECompatibility) then
  CheckListBox1.Checked[1] := True;
if (Delphi3 in IDECompatibility) then
  CheckListBox1.Checked[2] := True;

The cleaner, short and better way:

CheckListBox1.Checked[0] := (Delphi1 in IDECompatibility);
CheckListBox1.Checked[1] := (Delphi2 in IDECompatibility);
CheckListBox1.Checked[2] := (Delphi3 in IDECompatibility);

Now I want to do it the other way, to set the values.

Currently the only way I know is the long way:

if CheckListBox1.Checked[0] then
  IDECompatibility := IDECompatibility + [Delphi1]
else
  IDECompatibility := IDECompatibility - [Delphi1];

if CheckListBox1.Checked[1] then
  IDECompatibility := IDECompatibility + [Delphi2]
else
  IDECompatibility := IDECompatibility - [Delphi2];

if CheckListBox1.Checked[2] then
  IDECompatibility := IDECompatibility + [Delphi3]
else
  IDECompatibility := IDECompatibility - [Delphi3];

If possible I would like to do something like this:

IDECompatibility[Delphi1] := CheckListBox1.Checked[0]; // Array type required
IDECompatibility[Delphi2] := CheckListBox1.Checked[1]; // Array type required
IDECompatibility[Delphi3] := CheckListBox1.Checked[2]; // Array type required

There is the Exclude and Include members but I am unsure if these are going to be needed here or not.

So, as described above - Is there a easier way to define a Enum type based on a boolean value?

Thank you.


Solution

  • No, there is no array like access available for set type in Delphi at this time. I would suggest making a helper indexed property which can mimic array like access and which will hide a code needed to include or exclude an element from the set.

    From what I've seen so far, people usually prefix properties that has some elementary access by Is or Has prefixes. In your case I would follow this rule and make a property called HasIDECompatibility or let's say IsIDECompatible. This property will be of Boolean type and will have a getter, by which you return the information whether the element is inside the internal set field or not. In setter it will either include or exclude the element into the set depending on the input value.

    In a more generalized code it would be:

    type
      TElement = (
        Element1,
        Element2,
        Element3
      );
      TElements = set of TElement;
    
      TMyClass = class
      private
        FElements: TElements;
        function GetElement(Kind: TElement): Boolean;
        procedure SetElement(Kind: TElement; Value: Boolean);
      public
        // this property is for direct access to the set field; if your class would
        // be a TComponent descendant and you'd publish this property, you'd see it
        // in the Object Inspector represented by a set of check boxes
        property Elements: TElements read FElements write FElements;
        // this property is just a helper for array like access to the internal set
        // field
        property HasElement[Kind: TElement]: Boolean read GetElement write SetElement;
      end;
    
    implementation
    
    { TMyClass }
    
    function TMyClass.GetElement(Kind: TElement): Boolean;
    begin
      Result := Kind in FElements;
    end;
    
    procedure TMyClass.SetElement(Kind: TElement; Value: Boolean);
    begin
      if Value then
        Include(FElements, Kind)
      else
        Exclude(FElements, Kind);
    end;
    

    And an example usage:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      MyClass: TMyClass;
    begin
      MyClass := TMyClass.Create;
      try
        // write elementary property value
        MyClass.HasElement[Element1] := CheckBox1.Checked;
        MyClass.HasElement[Element2] := CheckBox2.Checked;
        // read elementary property value
        CheckBox3.Checked := MyClass.HasElement[Element1];
        CheckBox4.Checked := MyClass.HasElement[Element2];
    
        // or you can access MyClass.Elements set at once as you were used to do
        // which gives you two ways to include or exclude elements to the set
      finally
        MyClass.Free;
      end;
    end;