- or how could I forget some set operators.
Recently a colleague of mine asked me to review some old code, and a line similar to the one below pop into my view as strange:
if (doorStates * [dsClosed, dsUnlocked] <> []) then
It had been so many years since I had used that specific syntax, that I completely forgot about some of the set operators in Pascal and Delphi - so I thought I would write up a small post on Sets in Pascal/Delphi.
In regards to the silly doorStates example above - here is a little riddle: When is a door not a door?
The theory on the subject is just basic algebra and useful in relational algebra also - so help me Codd.
A set variable in Pascal can hold up till 256 elements, which ordinal values can be 0..255. The type of the elements must all be the same, and be a scalar type - but not floating point numbers.
And compared to other variables can a set have none, 1 or multiple values, and values in a set is unique - in an array you can have duplicates.
Set types are defined with the SET OF keywords - like:
Type
TDigits = set of '0'..'9';
TGarmentColors = set of (Yellow, Green, Blue, Red, Black);
TDoorStates = set of (dsOpen, dsClosed, dsLock, dsUnLock, dsAjar);
TBelow50 = set of 0..49;
TLetters = set of 'A'-'Z';
So let us go through the various set operators one by one with some examples, and also add a couple that are not directly represented by a single operator.
Example set variables defined are - using just sets of integers to keep it simple:
A := [5, 3, 7, 9, 16];
B := [2, 6, 9, 1, 4];
C := [1..7, 9, 16];
Union
A ∪ B is in Pascal with as A + B so:
A + B = [1, 2, 3, 4, 5, 6, 7, 9, 16]
Difference
A ∖ B or A - B is in Pascal written as A - B so:
A - B = [3, 5, 7, 16]
Intersection
A ∩ B is in Pascal written as A * B, so:
A * B = [9]
Subset
A ⊂ C is in Pascal written as A <= C, so:
A <= C = True;
Superset
C ⊃ A is in Pascal written as C >= A, so:
C >= A = True;
Equality
C = A ∪ B is in Pascal written as C = A + B, so:
(C = A + B) = True;
Inequality (disjoint)
A ≠ B is in Pascal written as A <> B, so:
(A <> B) = True;
Membership
{3} ⊂ A could in Pascal be written as 3 in A, so:
3 in A = True;
Symmetric difference
A Δ B or A ⊕ B which is the same as (A ∪ B) - (A ∩ B), can in Pascal be written as (A + B) - (A * B), so:
(A + B) - (A * B) = [1, 2, 3, 4, 5, 6, 7, 16]
or
(A - B) + (B - A) = [1, 2, 3, 4, 5, 6, 7, 16]
Include
B ∪ {3} could in Pascal be written as Include(B, 3), so:
Include(B, 3);
B = [1, 2, 3, 4, 6, 9]
Exclude
C ∖ {5} or C - {5} could in Pascal be written as Exclude(C, 5), so:
Exclude(C, 5);
C = [1,2,3,4,6,7,9,16]
I did a small application to illustrate the operators, and it can be used as evaluator - on a 0..255 integer set. I will put it on GitHub, if it has any interest.
So I do like Pascal sets, I think the only drawback is that a set is restricted by 256 element and the ordinal value must also be within 0-255.
Coming back to the riddle: When It's A Jar.
Which is also the title of one of Tom Holts many funny books - which I highly recommend. Amazon link.
There are also many great Delphi books being published recently - which will fit great as a Christmas gift for your employees, if you are an employer or team lead.
/Enjoy
Nice overview!
ReplyDeleteOne small detail - there is absolutely no need to compare boolean result to True. One does not have to write "(C = A + B) = True" when "(C = A + B)" does the work.
Thanks Primož! I am aware that I would not need the = True, but it was just to illustrate what it evaluates to. I should have written a proper if statement, the line you point out could be mistaken as code.
Delete