Recent

Author Topic: Is there a conditional Set that uses a boolean in a single function call ?  (Read 3362 times)

440bx

  • Hero Member
  • *****
  • Posts: 3944
Re: Is there a conditional Set that uses a boolean in a single function call ?
« Reply #15 on: September 21, 2020, 09:49:23 pm »
BTW, why compiler 3.3.1 does not complain?
Code: Pascal  [Select][+][-]
  1.   procedure Any(const Anything);
  2.   procedure DoIt;
  3.   ...
  4. implementation
  5.  
  6. procedure Any(const Anything);
  7. begin
  8.  
  9. end;
  10.  
  11. procedure DoIt;
  12. begin
  13.   Any([fsItalic, fsBold]);  //unit1.pas(31,25) Error: Variable identifier expected
  14.   Any(Cardinal([fsItalic, fsBold]));  //ok
  15. end;
This a guess based on the way I've seen FPC treat parameters.  The procedure "Any" uses an untyped parameter ("Anything"), because of it being untyped, the compiler will pass a pointer to whatever the parameter "Anything" happens to be.  In the procedure DoIt, in the first statement, the compiler does _not_ create a temporary set it can take the address of and pass to "Any".  In the second statement, the result isn't a set, just an ordinal number and the compiler can easily put that on the stack and pass the address on the stack where that _number_ (not set) is located.

Put a different way, I've observed that FPC does _not_ create temporary sets on the fly.  That part is _not_ a guess, it's a fact.  That fact is where the above guess comes from.

Hopefully, one of the developers can confirm if the above guess is correct or not.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Is there a conditional Set that uses a boolean in a single function call ?
« Reply #16 on: September 21, 2020, 10:32:02 pm »
BTW, why compiler 3.3.1 does not complain?

At least the following fails with trunk on x86_64-win64 with the error you mentioned:

Code: Pascal  [Select][+][-]
  1. program tformal;
  2.  
  3. {$mode objfpc}
  4.  
  5. type
  6.   TFontStyle = (
  7.     fsItalic,
  8.     fsBold,
  9.     fsUnderlined,
  10.     fsStrikeOut
  11.   );
  12.   TFontStyles = set of TFontStyle;
  13.  
  14. procedure Any(const Anything);
  15. begin
  16.  
  17. end;
  18.  
  19. procedure DoIt;
  20. begin
  21.   Any([fsItalic, fsBold]);  //unit1.pas(31,25) Error: Variable identifier expected
  22.   Any(Cardinal([fsItalic, fsBold]));  //ok
  23. end;
  24.  
  25. begin
  26.  
  27. end.

Does this fail for you as well? Do you have a full, self contained example?

I have no clue about endianess. It would be nice if something like this (endian safe) would be part of FPC.

This should be endian safe, cause you're casting it to set type. If you'd work with bit offsets yourself you'd have to pay attention like the code for StringToSet does.

I think there's a fundamental missing operation here, which is being able to multiply an arbitrary set by a boolean to give the potential of clearing it without having to use conditionals (i.e. interrupt the flow of control).

If that operation worked, then xor (symmetric difference) could be used to set/reset an element without having to mess around with casts and without interrupting execution flow.

I don't get what you'd try to achieve here. Do you have a pseudo code example? (Also symmetric difference in Pascal is ><, not xor)

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Is there a conditional Set that uses a boolean in a single function call ?
« Reply #17 on: September 21, 2020, 10:48:49 pm »
This may have strayed a little but the initial idea was to be able to set a member of a SET via a condition in a simple call statement..

For example :

  ConditionSet(TheSet. A_Member_of_the_set, A_Boolean_condition);

  So the idea is to either Include a member in the set if true or Exclude a member in the set if false in a single term.

  It would make it so much easier to set the member from a Boolean source that is only known at runtime.

 I think an intrinsic feature could be made here for efficiency instead of trying to hack one that will work with any set.


The only true wisdom is knowing you know nothing

Blaazen

  • Hero Member
  • *****
  • Posts: 3237
  • POKE 54296,15
    • Eye-Candy Controls
Re: Is there a conditional Set that uses a boolean in a single function call ?
« Reply #18 on: September 21, 2020, 10:54:37 pm »
Code: Pascal  [Select][+][-]
  1. program tformal;
  2. {$mode objfpc}
  3.  
  4. type
  5.   TFontStyle = (
  6.     fsItalic,
  7.     fsBold,
  8.     fsUnderlined,
  9.     fsStrikeOut
  10.   );
  11.   TFontStyles = set of TFontStyle;
  12.  
  13. var aFS: TFontStyles;
  14.  
  15. procedure Any(const Anything);
  16. begin
  17.   aFS:=aFS+TFontStyles(Anything);
  18. end;
  19.  
  20. procedure DoIt;
  21. begin
  22.   //Any([fsItalic, fsBold]);  //unit1.pas(31,25) Error: Variable identifier expected
  23.   Any(Cardinal([fsItalic, fsBold]));  //ok
  24. end;
  25.  
  26. begin
  27.   writeln(Cardinal(aFS));
  28.   DoIt;
  29.   writeln(Cardinal(aFS));
  30. end.
Output:
Code: [Select]
[v1@nb-msi testset]$ fpc test.pas
Free Pascal Compiler version 3.3.1 [2020/09/04] for x86_64
Copyright (c) 1993-2020 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling test.pas
Linking test
29 lines compiled, 0.2 sec
[v1@nb-msi testset]$ ./test
0
3
[v1@nb-msi testset]$
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Is there a conditional Set that uses a boolean in a single function call ?
« Reply #19 on: September 22, 2020, 01:10:44 am »
Hi

It is too much to call the adding routine with a typecast.
Let that routine do the typecasting.

I have my above example adapted to your FontStyle(s) example:


Code: Pascal  [Select][+][-]
  1. type setOfByte = set of byte;
  2.  
  3. procedure TurnSetItem (var setofSomething; const Something; aOn : boolean );
  4. begin
  5.   if aOn then
  6.     setOfByte(setOfSomething) += [byte(Something)]
  7.   else
  8.     setOfByte(setOfSomething) -= [byte(SomeThing)];
  9. end;
  10.  
  11. procedure TForm1.Button4Click(Sender: TObject);
  12. var fst:  TFontStyles;
  13.     oneF : TFontStyle;
  14. S: string='';
  15. SItem : string;
  16. begin
  17. oneF := fsBold;
  18. fst := [fsItalic, fsUnderline];
  19. TurnSetitem (fst, oneF,true);
  20. for oneF in fst do
  21.    begin
  22.    writeStr(sItem,oneF);
  23.    s := s+SItem + ' ';
  24.    end;
  25. showMessage (s);
  26. end;                  

Winni

ASerge

  • Hero Member
  • *****
  • Posts: 2222
Re: Is there a conditional Set that uses a boolean in a single function call ?
« Reply #20 on: September 22, 2020, 01:35:37 am »
Code: Pascal  [Select][+][-]
  1. ...
  2. procedure SwitchSet(var ASet; const AItem; AOn: Boolean);
  3. type
  4.   TDummyEnum = (de0, de1, de2, de3, de4, de5, de6, de7, de8, de9, de10, de11, de12, de13, de14, de15,
  5.      de16, de17, de18, de19, de20, de21, de22, de23, de24, de25, de26, de27, de28, de29, de30, de31);
  6.   TDummySet = set of TDummyEnum;
  7. begin
  8.   if AOn then
  9.     Include(TDummySet(ASet), TDummyEnum(AItem))
  10.   else
  11.     Exclude(TDummySet(ASet), TDummyEnum(AItem));
  12. end;
  13. ...
In my opinion, the best solution. Fast. The only thing is, I would replace the long TDummyEnum with TDummyEnum = 0..31;

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Is there a conditional Set that uses a boolean in a single function call ?
« Reply #21 on: September 22, 2020, 03:02:17 am »
This will also not work with Constants.
I made an example using that example to show what I mean.
Code: Pascal  [Select][+][-]
  1. Type
  2.   Test = (one, two);
  3.   Dummy = 1..31;
  4.   DummySet = Set of Dummy;
  5.   Procedure SetDummy(Var TheSet; theValue:Byte; theState:Boolean) inline;
  6.    begin
  7.      Case TheState of
  8.       False :Exclude(DummySet(TheSet), Dummy(TheValue));
  9.       True  :Include(DummySet(TheSet), Dummy(TheValue));
  10.    end;
  11.   End;
  12. var
  13.   S:DummySet;
  14. begin
  15.    SetDummy(S, Ord(One),True);
  16.    SetDummy(S, 4, False);
  17. end;                                        
  18.  

 As you can see I was able to use a constant this way however, this leads to a problem because now the "One" in the enum could be coming from any ENUM that has  a "one" in it, In otherwords it may not belong to the SET that is being reference to.

 I am sure the compiler test to ensure the ENUM belongs to the set under normal conditions when compiling for constants.

 Like I said, this needs to be an intrinsic function so the compiler can do a check for correctness of ENUMS belonging to the set.
The only true wisdom is knowing you know nothing

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Is there a conditional Set that uses a boolean in a single function call ?
« Reply #22 on: September 22, 2020, 03:14:34 am »
Hi!

I knew that my solution was too simple for this forum.

K I S S

Winni

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Is there a conditional Set that uses a boolean in a single function call ?
« Reply #23 on: September 22, 2020, 09:26:25 am »
Code: Pascal  [Select][+][-]
  1. program tformal;
  2. {$mode objfpc}
  3.  
  4. type
  5.   TFontStyle = (
  6.     fsItalic,
  7.     fsBold,
  8.     fsUnderlined,
  9.     fsStrikeOut
  10.   );
  11.   TFontStyles = set of TFontStyle;
  12.  
  13. var aFS: TFontStyles;
  14.  
  15. procedure Any(const Anything);
  16. begin
  17.   aFS:=aFS+TFontStyles(Anything);
  18. end;
  19.  
  20. procedure DoIt;
  21. begin
  22.   //Any([fsItalic, fsBold]);  //unit1.pas(31,25) Error: Variable identifier expected
  23.   Any(Cardinal([fsItalic, fsBold]));  //ok
  24. end;
  25.  
  26. begin
  27.   writeln(Cardinal(aFS));
  28.   DoIt;
  29.   writeln(Cardinal(aFS));
  30. end.
Output:
Code: [Select]
[v1@nb-msi testset]$ fpc test.pas
Free Pascal Compiler version 3.3.1 [2020/09/04] for x86_64
Copyright (c) 1993-2020 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling test.pas
Linking test
29 lines compiled, 0.2 sec
[v1@nb-msi testset]$ ./test
0
3
[v1@nb-msi testset]$

The code you posted above compiles with 3.0.4, 3.2.0 and 3.3.1 and if I enable the other call to Any it fails in all three. So it's not a regression compared to 3.0.4 though of course one might argue whether it's correct that the second call works while the first does not.

Feel free to open a bug report maybe Jonas or Florian know why it behaves differently or if it's indeed supposed to be this way.

Blaazen

  • Hero Member
  • *****
  • Posts: 3237
  • POKE 54296,15
    • Eye-Candy Controls
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

 

TinyPortal © 2005-2018