Flipping Boolean Variables

Recently I found myself writing code like this a lot:

Prefs.ToolbarOptions.Visible := not Prefs.ToolbarOptions.Visible;

So I created a function to invert the state of boolean variables:

procedure BooleanToggle(var Value: Boolean);
begin
  Value := not Value;
end;

Now I can simplify each line to:

BooleanToggle(Prefs.ToolbarOptions.Visible);

I don’t know why I hadn’t thought of it before. Have I just duplicated some inbuilt function?

1 Like

I thought I was going to save a lot of time writing the same, then I realised most of my UI controls used properties rather than variables so then the the function wasn’t much use.

It would be great if Delphi could pass a property as a var param to a function, but it can’t.

Could do a record helper for boolean …

type
    TBoolHelper = record helper for boolean
       function  opp : boolean;
       procedure flip;
    end;

    function TBoolHelper.opp : boolean;
    begin
      result := not self
    end;

    procedure TBoolHelper.flip;
    begin
      self := not self;
    end;

[Edited]

@Paul_McGee that’s a really cool idea. I always forget about record helpers when thinking about solving problems and I think I need to pay more attention to how they can help.

Prefs.ToolbarOptions.Visible.flip;

Its much nicer syntax and works with properties. In many ways this should be part of the default helper for booleans (TBooleanHelper) as there isn’t much else you can do with a boolean.

I think we’re stuck with class.propery := class.property.opp;

Actually I think the problem with record helpers is that we’ve never been able to use more than one at a time for some reason. I’ve never understood this limitation but it always feels annoying that to make a new one you have to copy all the code from the default one into your special one.

Your code compiled for properties, i didn’t realise it didn’t actually change the value?

1 Like

Ah, helper records! I keep forgetting about them as my major project is still in XE.

This new one is in D12 so I’ll have to learn how to use them. Thanks.

You can use more than one at a time, just not for the same type. Since Embarcadero also have record helpers for the built in types - adding a record helper for boolean will disable the helper that embarcadero includes.

The one per type issue is a silly limitation - it’s a design problem, record helpers were added to help avoid interface breaking changes during updates, not for general use - but then they made them available because we were all asking - but never redesigned they way the compiler works with them (which has a limitation of 1 per type).

Not being able to extend existing helpers is kind of limiting. You’d have to add the overridden ones back in.

I did create some other helpers to do the CW and CCW for a (PDF) rotation variable. That was useful.

It seems you can inherit class helpers : Possible to "extend" or "inherit" an existing class/record helper? - Algorithms, Data Structures and Class Design - Delphi-PRAXiS [en]

But also for what it’s worth : ¯\(ツ)

type   
    bool2 = type boolean;

    TBHelper = record helper for bool2
       procedure flip;
    end;

    procedure TBHelper.flip;
    begin
      self := not self;
    end;

begin
    var a:bool2 = 'true';
    a.flip;
    boolean(a).ToString;
    var b := 'true';
    bool2(b).flip;
    b.ToString;
end.

It’d kinda look ok if we could write b as bool2.flip (imho)

The record helper is a bad idea because it will compile but not work if the property is backed by a getter instead of directly accessing the field. The procedure with the var parameter will at least stop the compilation.

Wait … we don’t want things to fail silently? :disappointed_relieved::skull:

It sound like helpers that change the state of the target are probably not the way to go then.

Maybe I’ll go back to the functions I first made.

Exactly - IMO this is a huge design flaw.