### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: [SOLVED]Generics and Include/Exclude  (Read 1137 times)

#### avk

• Sr. Member
• Posts: 325
##### [SOLVED]Generics and Include/Exclude
« on: September 22, 2020, 01:18:20 pm »
Suppose we need a procedure that, depending on the condition, includes or excludes a given element from the set and we want the procedure to accept any type of set as a parameter. Using a generic procedure for this seems like a good option:
Code: Pascal  [Select][+][-]
1. program test;
2.
3. {\$mode delphi}
4.
5. type
6.   TElem = (One, Two, Three, Four, Five);
7.   TSet  = set of TElem;
8.
9. procedure TurnSetElem<TSet, TElem>(var aSet: TSet; aElem: TElem; aOn: Boolean);
10. begin
11.   if aOn then
12.     Include(aSet, aElem)
13.   else
14.     Exclude(aSet, aElem);
15. end;
16.
17. var
18.   s: TSet = [];
19.   e: TElem;
20.
21. begin
22.   for e in s do
23.     WriteLn(e);
24.   TurnSetElem<TSet, TElem>(s, Two, True);
25.   TurnSetElem<TSet, TElem>(s, Five, True);
26.   for e in s do
27.     WriteLn(e);
28. end.
29.
compile-time error(both 3.2.0 and 3.3.1):
Code: Text  [Select][+][-]
1. test.lpr(12,5) Error: Type mismatch
2. test.lpr(14,5) Error: Type mismatch
3.

But if the procedure is slightly changed:
Code: Pascal  [Select][+][-]
1. procedure TurnSetElem<TSet, TElem>(var aSet: TSet; aElem: TElem; aOn: Boolean);
2. begin
3.   if aOn then
4.     aSet += [aElem]
5.   else
6.     aSet -= [aElem] ;
7. end;
8.
then it compiles and works as expected.

Why is there such discrimination?
« Last Edit: September 25, 2020, 05:36:15 pm by avk »

#### ASerge

• Hero Member
• Posts: 1693
##### Re: Generics and Include/Exclude
« Reply #1 on: September 22, 2020, 08:07:36 pm »
Code: Pascal  [Select][+][-]
1. {\$APPTYPE CONSOLE}
2. {\$MODE DELPHI}
3.
4. procedure TurnSetElem<TSet, TElem>(var ASet: TSet; AElem: TElem; AOn: Boolean);
5.
6.   procedure TurnSetUniveral(var ASet; const AItem; AOn: Boolean);
7.   type
8.     TItem = 0..31;
9.     TItemSet = set of TItem;
10.   begin
11.     if AOn then
12.       Include(TItemSet(ASet), TItem(AItem))
13.     else
14.       Exclude(TItemSet(ASet), TItem(AItem))
15.   end;
16.
17. begin
18.   TurnSetUniveral(ASet, AElem, AOn)
19. end;
20.
21. procedure Test;
22. type
23.   TElem = (One, Two, Three, Four, Five);
24.   TSet  = set of TElem;
25. var
26.   LSet: TSet = [];
27.   Elem: TElem;
28. begin
29.   for Elem in LSet do
30.     WriteLn(Elem);
31.   TurnSetElem<TSet, TElem>(LSet, Two, True);
32.   TurnSetElem<TSet, TElem>(LSet, Five, True);
33.   for Elem in LSet do
34.     WriteLn(Elem);
35. end;
36.
37. begin
38.   Test;
40. end.

#### avk

• Sr. Member
• Posts: 325
##### Re: Generics and Include/Exclude
« Reply #2 on: September 23, 2020, 06:26:15 am »
@ASerge, yeah, I've already seen code like this in this post. But the question is that the fact that the compiler does not accept Include/Exclude looks like a bug.
« Last Edit: September 23, 2020, 11:34:53 am by avk »

#### ASerge

• Hero Member
• Posts: 1693
##### Re: Generics and Include/Exclude
« Reply #3 on: September 23, 2020, 04:45:05 pm »
But the question is that the fact that the compiler does not accept Include/Exclude looks like a bug.
I thought you needed a general solution. And the question is not difficult to answer. Built-in functions Include and Exclude expect only sets. The addition operation can be overloaded, i.e. it is valid.

#### avk

• Sr. Member
• Posts: 325
##### Re: Generics and Include/Exclude
« Reply #4 on: September 23, 2020, 07:23:14 pm »
Built-in functions Include and Exclude expect only sets.

And what does it get if not a set?
Some time ago, such a stupid function(containing the built-in function Ord(), which accepts only ordinals)
Code: Pascal  [Select][+][-]
1. function GenSumOrd<T>(a, b: T): T;
2. begin
3.   Result := Ord(a) + Ord(b);
4. end;
5.
flatly refused to compile with any version of the compiler. It now compiles(if specialized with ordinal type), at least using a trunk compiler(it looks like the changes weren't merged in 3.2.1). It seems with Include/Exclude the same situation.

#### PascalDragon

• Hero Member
• Posts: 2418
• Compiler Developer
##### Re: Generics and Include/Exclude
« Reply #5 on: September 23, 2020, 10:02:04 pm »
Why is there such discrimination?

The thing is that intrinsics are made aware of generics on a case by case base. This way we can ensure that they handle generics as type safe as reasonably possible. In this case no one had needed them up to now, so no one implemented them.

Thus please report this as a bug.

#### avk

• Sr. Member
• Posts: 325
##### Re: Generics and Include/Exclude
« Reply #6 on: September 24, 2020, 05:50:36 am »
Thank you, done.

Code: Pascal  [Select][+][-]
1. type
2.   TSetUtil<TElem> = record
3.   type
4.     TSet = set of TElem;
5.     class procedure TurnElem(var aSet: TSet; aElem: TElem; aOn: Boolean); static;
6.   end;
7.
« Last Edit: September 24, 2020, 10:16:40 am by avk »

• Hero Member
• Posts: 10574
##### Re: Generics and Include/Exclude
« Reply #7 on: September 24, 2020, 08:29:29 am »
Note you may be able to use the new generic ifthen<> from sysutils in such a way? 3.2.0 +

#### PascalDragon

• Hero Member
• Posts: 2418
• Compiler Developer
##### Re: Generics and Include/Exclude
« Reply #8 on: September 24, 2020, 09:16:45 am »
Thank you, done.

Thank you.

I had thought a bit about that as well. Maybe I should adjust some restrictions a bit considering that we have a more template-like approach anyway.

#### avk

• Sr. Member
• Posts: 325
##### Re: Generics and Include/Exclude
« Reply #9 on: September 24, 2020, 10:14:08 am »
Note you may be able to use the new generic ifthen<> from sysutils in such a way?

I cannot figure out how I could use IfThen in this case. Maybe you can suggest some way?

I had thought a bit about that as well. Maybe I should adjust some restrictions a bit considering that we have a more template-like approach anyway.

Is something required of me?

• Hero Member
• Posts: 10574
##### Re: Generics and Include/Exclude
« Reply #10 on: September 24, 2020, 11:42:16 am »
I cannot figure out how I could use IfThen in this case. Maybe you can suggest some way?
Well, the idea is that the generic ifthen can take functional and procedural parameters to allow different execution paths.

That is how I designed it.

Afaik Michael has also added an example to the documentation for that based on my own example when I submitted that feature.
It may take a little redesign of your code, but to me it looks possible.
The signature is like this:
Code: Pascal  [Select][+][-]
1. generic function IfThen<T>(val:boolean;const iftrue:T; const iffalse:T) :T; inline; overload;
Where T can be anything, including procedural/functional types.

As usual, what Sven suggested gives even more options if implemented.
« Last Edit: September 24, 2020, 11:44:11 am by Thaddy »

#### PascalDragon

• Hero Member
• Posts: 2418
• Compiler Developer
##### Re: Generics and Include/Exclude
« Reply #11 on: September 24, 2020, 01:58:25 pm »
I had thought a bit about that as well. Maybe I should adjust some restrictions a bit considering that we have a more template-like approach anyway.

Is something required of me?

No, not really.

#### avk

• Sr. Member
• Posts: 325
##### Re: Generics and Include/Exclude
« Reply #12 on: September 25, 2020, 05:32:37 pm »
@PascalDragon, thanks a lot. The procedure now compiles and works as expected. But will these changes be merged in 3.2.1?

#### PascalDragon

• Hero Member
• Posts: 2418
• Compiler Developer
##### Re: [SOLVED]Generics and Include/Exclude
« Reply #13 on: September 26, 2020, 10:00:27 am »
I'll ask for them to be merged, yes, they shouldn't be that invasive.