Reputation: 1824
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:
Global constants (I will end up with 100s of new constants)
Global enumerated fields (even though I will end up with 100s of them, as with consts, they allow easier expansion of values if I add a third value)
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
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
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
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
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:
Upvotes: 2
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