开发者

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...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜