1. Technology
Send to a Friend via Email

Your suggestion is on its way!

An email with a link to:

http://delphi.about.com/od/beginners/a/delphi_set_type.htm

was emailed to:

Thanks for sharing About.com with others!

Understanding Delphi SET Type

if ModalResult in [mrYes, mrOk] then ...

By

Surfing the Net
blackred/E+/Getty Images

One of the Delphi language features not found in other modern languages is the notion of sets.

Delphi's set type is a collection of values of the same ordinal type.

A set is defined using the set of keyword:

 type
   TMagicNumber = 1..34;
   TMagicSet = set of TMagicNumber;
 var
   emptyMagicSet : TMagicSet;
   oneMagicSet : TMagicSet;
   anotherMagicSet : TMagicSet;
 begin
   emptyMagicSet := [];
   oneMagicSet := [1, 18, 24];
   anotherMagicSet := [2, 5, 19];
 
   if 1 in oneMagicSet then ShowMessage('1 is magic, part of oneMagicSet') ;
 
 end;
 
Set types are usually defined with subranges.

In the above example, the TMagicNumber is a custom subrange type allowing variables of the TMagicNumber type to receive values from 1 to 34. Simply put, a subrange type represents a subset of the values in another ordinal type.

Possible values of the set type are all the subsets of the base type, including the empty set.

A limitation on sets is that they can hold up to 255 elements.

In the above example, the TMagicSet set type is a set of TMagicNumber elements - integer numbers from 1 to 34.

The declaration TMagicSet = set of TMagicNumber is equal to the following declaration: TMagicSet = set of 1..34.

Set type variables

In the above example, the variables emptyMagicSet, oneMagicSet and anotherMagicSet are sets of TMagicNumber.

To assign a value to a set type variable, use the square brackets and list all the elements of the set. As in:

 oneMagicSet := [1, 18, 24]; 

Note 1: every set type variable can hold the empty set, denoted by [].

Note 2: the order of the elements in a set has no meaning, nor is it meaningful for an element (value) to be included twice in a set.

The IN keyword

To test if an element is included in the set (variable) use the IN keyword:
 if 1 in oneMagicSet then ... 

Set Operators

The same way you can sum two numbers, you can have a set that is the sum of two sets. With sets you event have more operators:
  • + returns the union of two sets.
  • - returns the difference of two sets.
  • * returns the intersection of two sets.
  • = return true if two sets are equal - have the same elemement.
  • <= returns true if the first set is a subset of the second set.
  • >= returns true if the first set is a superset of the second set.
  • <> returns true if two sets are non-identical.
  • IN returns true if an element is included in the set.
Here's an example:
   emptyMagicSet := oneMagicSet + anotherMagicSet;
   emptyMagicSet := emptyMagicSet - [1];
   emptyMagicSet := emptyMagicSet + [5,10];
 
   if emptyMagicSet = [2,5,10,18,19,24] then
   begin
     emptyMagicSet := emptyMagicSet * oneMagicSet;
 
     ShowMessage(DisplayElements(emptyMagicSet)) ;
   end;
 
Will the ShowMessage procedure be executed? If so, what will be displayed?

Here's the implementation of the DisplayElements function:

 function DisplayElements(magicSet : TMagicSet) : string;
 var
   element : TMagicNumber;
 begin
   for element in magicSet do
     result := result + IntToStr(element) + ' | ';
 end;
 
Hint: yes. Displayed: "18 | 24 |".

Integers, Characters, Booleans

Of course, when creating set types you are not restricted to integer values. Delphi ordinal types include character and boolean values.

To prevent users to type alpha keys, add this line in the OnKeyPress of an edit control:

 if Key in ['a'..'z'] + ['A'..'Z'] then Key := #0
 

Sets with Enumerations

A commonly used scenario in Delphi code is to mix both enumerated types and set types.

Here's an example:

 type
   TWorkDay = (Monday, Tuesday, Wednesday, Thursday, Friday) ;
   TDaySet = set of TWorkDay;
 var
   days : TDaySet;
 begin
   days := [Monday, Friday];
 
   days := days + [Tuesday, Thursday] - [Friday];
 
   if Wednesday IN days then ShowMessage('I love Wednesday!') ;
 

Question: will the message be displayed? Answer: no :(

Sets in Delphi Control Properties

When you need to apply "bold" to the font used in TEdit controls, you either use the Object Inspector or the following code:
 Font.Style := Font.Style + [fsBold];
 
The Font's Style property is a set type property! Here's how it is defined:
 type
   TFontStyle = (fsBold, fsItalic, fsUnderline, fsStrikeOut) ;
 
   TFontStyles = set of TFontStyle;
 
 ...
   property Style: TFontStyles ...
 
So, an enumerated type TFontStyle is used as the base type for the set type TFontStyles. The Style property of the TFont class is of type TFontStyles - therefore a set type property.

Another example includes the result of the MessageDlg function. A MessageDlg function is used to bring up a message box and obtain the user's response. One of the parameters of the function is the Buttons parameter of type TMsgDlgButtons.

TMsgDlgButtons is defined as a set of (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore, mbAll, mbNoToAll, mbYesToAll, mbHelp).

If you display a message to the user containing Yes, OK and Cancel buttons and you want to execute some code if either the Yes or Ok buttons were clicked you can use the next code:

 if MessageDlg('Learning about Sets!', mtInformation, [mbYes, mbOk, mbCancel], 0) in [mrYes, mrOK] then ...
 

Final word: sets are great. Sets might appear confusing to a Delphi beginner, but as soon as you start using set type variables you will find out they provide much more then it sounded in the the beginning. At least I have :))

©2014 About.com. All rights reserved.