Mike Torrettinni
Mike Torrettinni

Reputation: 1824

How to initialize Boolean type to be used by local variables?

I am trying to change how I use Boolean parameters to have meaningful names, so I don't need to check every method what True/False mean. In this example I use True/False:

procedure ProcessData(Param1, Param2: string; CreateOnEmpty: boolean = False);

procedure TForm1.Button1Click(Sender: TObject);
begin
  ProcessData(P1, P2, True);  // when CreateOnEmpty should be True
  ProcessData(P1, P2);        // when CreateOnEmpty should be False
  ProcessData(P1, P2, False); // when CreateOnEmpty should be False
end;

But in this case I need to look up ProcessData method to see what True/False parameters mean, do.

So, I started with this example, to assign meaningful names to parameters:

procedure TForm1.Button2Click(Sender: TObject);
var
  vCreateWhenEmpty: boolean;
  vDontCreateWhenEmpty: boolean;
begin
  // Init control params
  vCreateWhenEmpty := True;
  vDontCreateWhenEmpty := False;

  ProcessData(P1, P2, vCreateWhenEmpty);     // When CreateOnEmpty should be True
  ProcessData(P1, P2, vDontCreateWhenEmpty); // When CreateOnEmpty should be False
end;

But, I would like to avoid Initalizing local variables and was thinking of something like this:

procedure TForm1.Button3Click(Sender: TObject);

Type
  TBoolTrue = Boolean = True;    // Init to True and all local vars will be True
  TBoolFalse = Boolean = False;  // Init to False and all local vars will be False

var
  vCreateWhenEmpty: TBoolTrue;      // Variable should default to True
  vDontCreateWhenEmpty: TBoolFalse; // Variable should default to False
begin
  ProcessData(P1, P2, vCreateWhenEmpty);     // When CreateOnEmpty should be True
  ProcessData(P1, P2, vDontCreateWhenEmpty); // When CreateOnEmpty should be False
end;

So, I could skip assigning value True/False.

I have 100s of methods that accept Boolean parameters, so 100s of constants or global variables which I can use as parameters sound overkill.

Is it possible to somehow initialize Boolean type to True/False or avoid initializing local variables with some other trick?

EDIT:

I relaized in example I set Boolean types as local types, I meant to set them as global so they are only set once and not each time in each method. So, this would be global and not local:

Type
      TBoolTrue = Boolean = True;    // Init to True and all local vars will be True
      TBoolFalse = Boolean = False;  // Init to False and all local vars will be False

EDIT 2:

I hope the question doesn't get closed as there are some good suggestion in the answers. So my options are:

DECISION

Even though Sir Rufo's trick on how to do what I was thinking of was unique, I realized I was trying to achieve something that is not in realm of current Delphi versions. So, I will use a combination of consts and enumerated types and apply only where really necessary, not everywhere and will avoid 100s of global, local variables.

Upvotes: 3

Views: 2462

Answers (5)

dummzeuch
dummzeuch

Reputation: 11217

In addition to what others already suggested, you could use enums instead of booleans, if you can change the implementation of your ProcessData method:

type
  TCreateDisposition = (cdDontCreate, cdCreateIfEmpty);

procedure ProcessData(Param1, Param2: string; CreateDisposition: TCreateDisposition);

Upvotes: 3

Sir Rufo
Sir Rufo

Reputation: 19106

There is no way to auto initialize local variables.

But we can create a record that will behave like an auto initialized local variable.

type
  TBoolDefaultTrue = record
  private const
    InitializedFlag = '*';
    DefaultValue = True;
  private
    FIsInitialized: string;
    FValue: Boolean;
    procedure EnsureInitialized;
  public
    class operator implicit ( const v: Boolean ): TBoolDefaultTrue;
    class operator implicit ( const v: TBoolDefaultTrue ): Boolean;
  end;

procedure EnsureInitialized;
begin
  if FIsInitialized = ''
  then 
    begin
      FValue := DefaultValue;
      FIsInitialized := InitializedFlag;
    end;
end;

class operator TBoolDefaultTrue.Implicit( const v: Boolean ): TBoolDefaultTrue;
begin
  Result.FValue := v;
  Result.FIsInitialized := InitializedFlag;
end;

class operator TBoolDefaultTrue.Implicit( const v: TBoolDefaultTrue ): Boolean;
begin
  v.EnsureInitialized;
  Result := v.FValue;
end;

and you can use it without changing your method signature

procedure TForm1.Button3Click(Sender: TObject);
var
  vCreateWhenEmpty: TBoolDefaultTrue;
  vDontCreateWhenEmpty: TBoolDefaultFalse;
begin
  ProcessData(P1, P2, vCreateWhenEmpty);     // When CreateOnEmpty should be True
  ProcessData(P1, P2, vDontCreateWhenEmpty); // When CreateOnEmpty should be False
end;

This is only one option you can choose, but to me that is not the one I would prefer for this. I like the enum way as Ken describes in his answer. I would only choose different names.

TProcessDataOption = ( pdoDontCreateWhenEmpty, pdoCreateWhenEmpty );

But that is only sugar

Upvotes: 4

Uwe Raabe
Uwe Raabe

Reputation: 47714

As others said there is currently no way to initialize local variables, but the real question is why that should be variables at all. It is my understanding from your code that after initializing those variables in code they will never change their value. Also the method does not declare these parameters as variables. In this case, it can also be accomplished by local constants (just to avoid global constants). So instead of declaring local variables and initialize them in code, just declare local constants.

procedure TForm1.Button3Click(Sender: TObject);
const
  cCreateWhenEmpty = True;
  cDontCreateWhenEmpty = False;
begin
  ProcessData(P1, P2, cCreateWhenEmpty);     // When CreateOnEmpty should be True
  ProcessData(P1, P2, cDontCreateWhenEmpty); // When CreateOnEmpty should be False
end;

On the long run I would also suggest declared enumeration types used as parameters, but in case you are not in the position to change the declaration, the above solution should match the requirements mentioned in your question quite well.

Upvotes: 7

user1970794
user1970794

Reputation: 263

I think you should leave it how you have it. If you want to see what the name of the parameter is you can simply use code insight to do so.

If you don't already use these then you should start and make your life way easier:

  • Ctrl + Shift + Spacebar Invoke code parameter hints Delphi 5 and up
  • Ctrl + Shift + UpArrow Navigate to method implementation/declaration Delphi 5 and up
  • Ctrl + Click Goes to declaration.

Upvotes: 2

Ken White
Ken White

Reputation: 125707

There's no way to auto-initialize local variables. You'll have to do so in code, or (despite not wanting to) use const instead of types, declared at the same scope as the function that will use them.

const
  vCreateWhenEmpty = True;
  vDontCreateWnenEmpty = False;

procedure ProcessData(Param1, Param2: string; CreateOnEmpty: boolean = False);

Later:

  ProcessData(P1, P2, vCreateWhenEmpty); 
  ProcessData(P1, P2, vDontCreateWhenEmpty);

I personally would replace the Boolean variables with an enumerated type with a common prefix.

type
  TProcessDataCreateOpt = (coCreate, coSkip);

  procedure ProcessData(Param1, Param2: string; CreateOpt: TProcessDataCreateOpt = coSkip);

This makes it much more readable, Code Insight and Code Completion can help you with the proper values, and you don't need any local or global variables at all.

Upvotes: 10

Related Questions