Declaring block level variables for branches in delphi
In Delphi prism we can declare variables that is only needed in special occasions.
eg: In prism
If acondition then
begin
var a :Integer;
end;
a := 3; //this line will produce error. because a will be created only when the condition is true
Here 'a' cannot be assigned with 3 because it is nested inside a branch. How can we declare a va开发者_运维百科riable which can be used only inside a branch in delphi win32. So i can reduce memory usage as it is only created if a certain condition is true;
If reduced memory usage is not a problem what are the draw backs we have (or we don't have)
The premise of your question is faulty. You're assuming that in languages where block-level variables are allowed, the program allocates and releases memory for those variable when control enters or leaves those variables' scopes. So, for example, you think that when acondition
is true, the program adjusts the stack to make room for the a
variable as it enters that block. But you're wrong.
Compilers calculate the maximum space required for all declared variables and temporary variables, and then they reserve that much space upon entry to the function. Allocating that space is as simple as adjusting the stack pointer; the time required usually has nothing to do with the amount of space being reserved. The bottom line is that your idea won't actually save any space.
The real advantage to having block-level variables is that their scopes are limited.
If you really need certain variables to be valid in only one branch of code, then factor that branch out to a separate function and put your variables there.
The concept of Local Variable Declaration Statements like in Java is not supported in Delphi, but you could declare a sub-procedure:
procedure foo(const acondition: boolean);
procedure subFoo;
var
a: integer;
begin
a := 3;
end;
begin
If acondition then
begin
subFoo;
end;
end;
There is no way in Delphi to limit scope of an variable to less than entire routine. And in case of a single integer variable it doesn't make sense to worry about it... But in case of large data structure you should allocate it dynamically, not statically, ie instead of
var integers: array[1..10000]of Integer;
use
type TIntArray: array of Integer;
var integers: TIntArray;
If acondition then
begin
SetLength(integers, 10000);
...
end;
Beware that it could only be "syntactic sugar". The compiler may ensure you don't use the variable outside the inner scope, but that doesn't mean it could save memory. The variable may be allocated on the stack in the procedure entry code anyway, regardless if it is actually used or not. AFAIK most ABI initialize the stack on entry and clean it on exit. Manipulating the stack in a much more complex way while the function is executing including taking care of different execution paths may be even less performant - instead of a single instruction to reserve stack space you need several instruction scattered along code, and ensure the stack is restored correctly adding more, epecially stack unwinding due to an exception may become far more complex. If the aim is to write "better" code because of better scope handling to ensure the wrong variable is not used in the wrong place it could be useful, but if you need it as a way to save memory it could not be the right way.
You can emulate block-level variables with the (dreaded) with
statement plus a function returning a record. Here's a bit of sample code, written in the browser:
type TIntegerA = record
A: Integer;
end;
function varAInteger: TIntegerA;
begin
Result.A := 0;
end;
// Code using this pseudo-local-variable
if Condition then
with varAInteger do
begin
A := 7; // Works.
end
else
begin
A := 3; // Error, the compiler doesn't know who A is
end;
Edit to clarify this proposition
Please note this kind of wizardry is no actual replacement for true block-level variables: Even those they're likely allocated on stack, just like most other local variables, the compiler is not geared to treat them as such. It's not going to do the same optimizations: a returned record will always be stored in an actual memory location, while a true local variable might be associated with a CPU register. The compiler will also not let you use such variables for "for"
statements, and that's a big problem.
Having commented all that - there is a party trick that Delphi has that has far more uses than a simple local variable and may achieve your aim:
function Something: Integer;
begin
// don't want any too long local variables...
If acondition then
asm
// now I have lots of 'local' variables available in the registers
mov EAX, @AnotherVariable //you can use pascal local variables too!
// do something with the number 3
Add EAX, 3
mov @Result, EAX
jmp @next
@AnotherVariable: dd 10
@next:
end;
end;
end;
:)) bit of a pointless example...
精彩评论