Saturday, 28 November 2020

A Set back?

- 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

2 comments:

  1. Nice overview!

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

    ReplyDelete
    Replies
    1. 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