Lazarus

Free Pascal => General => Topic started by: Blaazen on May 09, 2014, 05:48:53 pm

Title: Sets - shorter expression
Post by: Blaazen on May 09, 2014, 05:48:53 pm
Hello,

do I have any lack of Pascal languge? Is this possible to write in one line?
I mean some type-saving way to control one item of set with boolean.
Code: [Select]
type
  TOption = (oOne, oTwo, oThree);
  TOptions = set of Option;
...
if (Sender as TCheckBox).Checked
    then Options:=Options+[oThree]
    else Options:=Options-[oThree];     
Thanks.
Title: Re: Sets - shorter expression
Post by: typo on May 09, 2014, 06:20:10 pm
Do you refer to the set operators? They are OK.
Title: Re: Sets - shorter expression
Post by: bigeno on May 09, 2014, 06:25:12 pm
Do you mean something in this way ?
Code: [Select]
  Options[oThree]:=(Sender as TCheckBox).Checked;
if yes, I think this is not possible.
Title: Re: Sets - shorter expression
Post by: taazz on May 09, 2014, 06:33:07 pm
personally I have an ever growing set of iif functions to use in such cases eg
Code: [Select]
function IIF(Check :Boolean; TrueResult, FalseResult :Integer):Integer;overload;inline;
function IIF(Check :Boolean; TrueResult, FalseResult :String):String;overload;inline;
....
implementation
function IIF(Check :Boolean; TrueResult, FalseResult :String):String;overload;inline;
begin
  If Check then Result := TrueResult else Result := FalseResult;
end;
......

but in this case I would do something like this.
Code: [Select]
function IIF(const Check :Boolean; const aSet:TOptions; const aOpt :TOption):TOptions;overload;inline;
begin
  Result := aSet;
  if Check then Include(Result, aOpt) else Exclude(Resut, aOpt)
end;
And its use looks like
Code: [Select]
Options := iif((Sender as TCheckBox).Checked,Options,oThree);
Title: Re: Sets - shorter expression
Post by: Blaazen on May 09, 2014, 06:48:52 pm
Thanks. In past I used function too, I named it SwitchOption instead of IIF. I hoped there exists some trick with set operators. It seems that Mr. Wirth omitted this.  :-[
Title: Re: Sets - shorter expression
Post by: Mike.Cornflake on May 09, 2014, 07:00:22 pm
I see no practical use for the following code, and would normally use your form of code, however - the challenge was raised :-) 
More set up time, but only one line of code.  In your case of course you would use (Sender as TCheckBox).Checked instead of bFlag...

Code: [Select]
Procedure TForm1.Button1Click(Sender: TObject);
Type
  TOption = (oOne, oTwo, oThree);
  TOptions = set of TOption;
Var
  Options: TOptions;
  bFlag: Boolean;
Const
  LU_Option: Array[Boolean] of TOptions = ([], [oThree]);
Begin
  Options := [oOne, oTwo, oThree];
  bFlag := False;

  Options := Options - [oThree] + LU_Option[bFlag];
End; 
LU is shorthand for Look Up
I don't think Mr Wirth did too bad :-)
Title: Re: Sets - shorter expression
Post by: bigeno on May 09, 2014, 07:16:58 pm
Nice  8)
Title: Re: Sets - shorter expression
Post by: Blaazen on May 09, 2014, 07:42:25 pm
I observed that other Pascal compiler (Delphi, GNU Pascal) cannot do it too. And it's not possible to hack it via Variant.
Title: Re: Sets - shorter expression
Post by: BeniBela on May 09, 2014, 11:57:04 pm
Code: [Select]
PByte(@Options + ord(oThree) div 8)^ := (PByte(@Options + ord(oThree) div 8)^ or (1 shl ord(oThree))) and ((ord(bFlag)*$FF or not (1 shl ord(oThree)))) ;
Title: Re: Sets - shorter expression
Post by: Mike.Cornflake on May 10, 2014, 10:52:11 am
:-)  Brilliant.  I've absolutely no clue how that code works, but at least you can easily change the option you're changing which is a distinct advantage over mine :-)
Title: Re: Sets - shorter expression
Post by: Martin_fr on May 10, 2014, 12:41:17 pm
Quote
Code: [Select]
PByte(@Options + ord(oThree) div 8)^

I am not sure this is endian save. So it may not work on all architectures.
Title: Re: Sets - shorter expression
Post by: eny on May 10, 2014, 01:44:02 pm
Code: [Select]
PByte(@Options + ord(oThree) div 8)^ := (PByte(@Options + ord(oThree) div 8)^ or (1 shl ord(oThree))) and ((ord(bFlag)*$FF or not (1 shl ord(oThree)))) ;
The person that writes this in code that I'm reviewing, gets fired  8)
Title: Re: Sets - shorter expression
Post by: Mike.Cornflake on May 10, 2014, 02:36:25 pm
Code: [Select]
PByte(@Options + ord(oThree) div 8)^ := (PByte(@Options + ord(oThree) div 8)^ or (1 shl ord(oThree))) and ((ord(bFlag)*$FF or not (1 shl ord(oThree)))) ;
The person that writes this in code that I'm reviewing, gets fired  8)
Ahh, but the point wasn't to produce reviewable code, but to get it onto one line.  Think of this as the obfuscated pascal competition.
(Sorry Blaazen, I appear to have hijacked your thread.  No disrepect was intended, just got excited by the challenge :) )
Title: Re: Sets - shorter expression
Post by: BeniBela on May 10, 2014, 02:48:47 pm
The person that writes this in code that I'm reviewing, gets fired  8)

It is the multiplication, isn't it?

Far too inefficient for this task

Fixed it  8-)

Code: [Select]
PByte(@Options + ord(oThree) div 8)^ := (PByte(@Options + ord(oThree) div 8)^ or (1 shl ord(oThree))) and not (ord(not bFlag) shl ord(oThree)) ;
oh, crap, forgot the mod:

Code: [Select]
PByte(@Options + ord(oThree) div 8)^ := (PByte(@Options + ord(oThree) div 8)^ or (1 shl (ord(oThree) mod 8))) and not (ord(not bFlag) shl (ord(oThree) mod 8)) ;
Title: Re: Sets - shorter expression
Post by: Martin_fr on May 10, 2014, 03:12:22 pm
1) If it was just about "on one line": Remove the line breaks, keep the original if.
Line breaks are for the human orly, so you can put the whole unit in one line, if you want.

2) from the OP:
Quote
I mean some type-saving way to control one item of set with boolean.

Probably meant "to save typing" rather than "save the type" (as in pascal being a strongly typed language).
But in either case: the whole PByte casting stuff, does not do either of that, or does it?

Quote
Code: [Select]
Options:=Options+[oThree]
If Options is a variable then using Include/Exclude may save a tiny bit of typing. But not much.

If you have lots of statements like that, all for the same type, write a helper function, or override an operator, or write a type helper.....
Title: Re: Sets - shorter expression
Post by: BeniBela on May 10, 2014, 03:16:22 pm

But in either case: the whole PByte casting stuff, does not do either of that, or does it?

It does, if you put it in a function

And you only need a single function, not a new one for every set-of-type
Title: Re: Sets - shorter expression
Post by: Martin_fr on May 10, 2014, 03:25:40 pm
Here is an Operator based approach. Makes only sense, if you have lots of operations on the same type....

Code: [Select]
program Project1;
type
  TOption = (oOne, oTwo, oThree);
  TOptions = set of TOption;

  TOptionModifier = record
    opt:TOption;
    act: Boolean;
  end;

operator * (a: TOption; b: Boolean) c:TOptionModifier;
begin
  c.opt := a;
  c.act := b;
end;

operator + (a: TOptions; b:TOptionModifier) c:TOptions;
begin
  if b.act
  then c := a + [b.opt]
  else c := a - [b.opt];
end;

var options: TOptions;

begin
  Options:=[];
  Options:=Options+oThree*True;
  writeln(oThree in options);
  Options:=Options+oThree*False;
  writeln(oThree in options);
end.
Title: Re: Sets - shorter expression
Post by: Martin_fr on May 10, 2014, 03:33:46 pm
It does, if you put it in a function

And you only need a single function, not a new one for every set-of-type
[/quote]

To make it ONE function, you need either untyped params, or call it with Foo(@Options, ord(OThree).

Either will remove type checking (one of the advantages of pascal), and allow you to specify a enum that does not belong to the same type as used for the set.
Then you may as well choose a language that has no type checking to begin with.

It also will not work, if "Options" is a property. No function will (unless it is a published property, and  RTTI is used (specifying property as string/name))