diferença entre var e out

Delphi

25/07/2007

estou tentando desenvolver um exemplo que demonstre a diferença entre
a passagem de parametros out e var.

eu achava que o out deveria inicializar as variaveis com zero e não considerar o valor que está sendo passada a elas. Mas não consegui simular a diferença. Parece que o out é a mesmissima coisa que o var.

Alguem poderia me explicar qual a diferença entre passagem de parametros via var e out? o que dá pra fazer com um que não dá com outro?

Eis o meu código:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private

  public

    procedure Teste1(x: Integer);
    procedure Teste2(var x: Integer);
    procedure Teste3(out x: Integer);
    procedure Teste4(x: PInteger);
  end;

var
  Form1: TForm1;

  //testar sem inicializar para usar lixo de memoria
  x1: Integer = 5;

const
    INCREMENTO = 2;

implementation

{$R *.dfm}

procedure TForm1.Teste1(x: Integer);
begin
    //x := 1;
    ShowMessage(´Antes X1 = ´ + IntToStr(X));
    x := x +  INCREMENTO;
    ShowMessage(´Depois X1 = ´ + IntToStr(X));
end;

procedure TForm1.Teste2(var x: Integer);
begin
    //x := 1;
    ShowMessage(´Antes X2 = ´ + IntToStr(X));
    x := x +  INCREMENTO;
    ShowMessage(´Depois X2 = ´ + IntToStr(X));
end;

procedure TForm1.Teste3(out x: Integer);
begin
    //x := 1;
    ShowMessage(´Antes X3 = ´ + IntToStr(X));
    x := x +  INCREMENTO;
    ShowMessage(´Depois X3 = ´ + IntToStr(X));
end;

procedure TForm1.Teste4(x: PInteger);
begin
    //x^ := 1;
    ShowMessage(´Antes X4 = ´ + IntToStr(X^));
    x^ := x^ + INCREMENTO;
    ShowMessage(´Depois X4 = ´ + IntToStr(X^));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
    //usando sempre a mesma variavel
    Teste1(x1);
    ShowMessage(´Externamente X1 = ´ + IntToStr(X1));
    Teste2(x1);
    ShowMessage(´Externamente X2 = ´ + IntToStr(X1));
    Teste3(x1);
    ShowMessage(´Externamente X3 = ´ + IntToStr(X1));
    Teste4(@x1);
    ShowMessage(´Externamente X4 = ´ + IntToStr(X1));
end;

end.


valew!


Vitor Rubio

Vitor Rubio

Curtidas 0

Respostas

Leonardobhbr

Leonardobhbr

25/07/2007

The Out directive identifies a function or procedure parameter as being a variable reference for outputting to only.

It allows a routine to return data to a variable of caller in addition to the Result value available in functions.

It is equivalent to Var except that the value should not be changed by the routine.

Delphi does not seem to enforce this, nor does it seem to enforce the need to assign a value.


GOSTEI 0
Vitor Rubio

Vitor Rubio

25/07/2007

tudo bem, isso está escrito no help do Delphi 7, mas, indo mais a fundo, a ideia basica por traz do out, em qualquer linguagem, é agir como se fosse o var, retornando o valor real da variavel a procedure chamadora, porem ignorando o valor inicial desta, e não usando-o como no caso de var.

só que isso só funciona para records, para variavies primitivas, como um integer, nada feito. Com objects eu não testei.

Execute esse código para você ter uma ideia do que estou falando: precisará de uma form com um memo e um button.

{
    conclusão: out só se aplica somente a records

}
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
    TCliente = record
        nome: string;
        email: string;
    end;

    PCliente = ^TCliente;

  TForm1 = class(TForm)
    Memo1: TMemo;
    btOk: TButton;
    procedure btOkClick(Sender: TObject);
  private
    procedure PrintResp(resp: string);
  public

    procedure Teste1(x: Integer);
    procedure Teste2(var x: Integer);
    procedure Teste3(out x: Integer);
    procedure Teste4(x: PInteger);
    procedure Teste5(const x: Integer);

    procedure TesteCli1(x: TCliente);
    procedure TesteCli2(var x: TCliente);
    procedure TesteCli3(out x: TCliente);
    procedure TesteCli4(x: PCliente);
    procedure TesteCli5(const x: TCliente);
    
  end;

var
  Form1: TForm1;

  //testar sem inicializar para usar lixo de memoria
  x1: Integer = 5;
  cli1:  TCliente;


const
    INCREMENTO = 2;

implementation

{$R *.dfm}

procedure TForm1.Teste1(x: Integer);
begin
    //x := 1;
    PrintResp(´***Por Valor***´);
    PrintResp(´Antes X1 = ´ + IntToStr(X));
    x := x +  INCREMENTO;
    PrintResp(´Depois X1 = ´ + IntToStr(X));
end;

procedure TForm1.Teste2(var x: Integer);
begin
    //x := 1;
    PrintResp(´***Por Referência (var)***´);
    PrintResp(´Antes X2 = ´ + IntToStr(X));
    x := x +  INCREMENTO;
    PrintResp(´Depois X2 = ´ + IntToStr(X));
end;

procedure TForm1.Teste3(out x: Integer);
begin
    //x := 1;
    PrintResp(´***Por Referência (out)***´);
    PrintResp(´Antes X3 = ´ + IntToStr(X));
    x := x +  INCREMENTO;
    PrintResp(´Depois X3 = ´ + IntToStr(X));
end;

procedure TForm1.Teste4(x: PInteger);
begin
    //x^ := 1;
    PrintResp(´***Por Referência (ponteiro)***´);
    PrintResp(´Antes X4 = ´ + IntToStr(X^));
    x^ := x^ + INCREMENTO;
    PrintResp(´Depois X4 = ´ + IntToStr(X^));
end;


procedure TForm1.Teste5(const x: Integer);
begin
    PrintResp(´***Por constante***´);
    //não dá pra mudar o valor de x aqui
    //x := 1;
    PrintResp(´Antes X5 = ´ + IntToStr(X));
    //x := x + INCREMENTO;
    PrintResp(´Depois X5 = ´ + IntToStr(X));
end;

procedure TForm1.btOkClick(Sender: TObject);
begin
    //usando sempre a mesma variavel
    Teste1(x1);
    PrintResp(´Externamente X1 = ´ + IntToStr(X1));
    PrintResp(´---------------------------------------´);
    PrintResp(´´);

    Teste2(x1);
    PrintResp(´Externamente X2 = ´ + IntToStr(X1));
    PrintResp(´---------------------------------------´);
    PrintResp(´´);

    Teste3(x1);
    PrintResp(´Externamente X3 = ´ + IntToStr(X1));
    PrintResp(´---------------------------------------´);
    PrintResp(´´);

    Teste4(@x1);
    PrintResp(´Externamente X4 = ´ + IntToStr(X1));
    PrintResp(´---------------------------------------´);
    PrintResp(´´);

    Teste5(x1);
    PrintResp(´Externamente X5 = ´ + IntToStr(X1));
    PrintResp(´---------------------------------------´);
    PrintResp(´´);




    cli1.nome := ´vitor´;
    cli1.email := ´vitorrubio@uol.com.br´;


    TesteCli1(Cli1);
    PrintResp(´Externamente Cli1:´+#13109 +  ´Nome: ´ + Cli1.nome + 13109 + ´Email: ´ + Cli1.email);
    PrintResp(´---------------------------------------´);
    PrintResp(´´);

    TesteCli2(Cli1);
    PrintResp(´Externamente Cli2:´+13109 +  ´Nome: ´ + Cli1.nome + 13109 + ´Email: ´ + Cli1.email);
    PrintResp(´---------------------------------------´);
    PrintResp(´´);

    TesteCli3(Cli1);
    PrintResp(´Externamente Cli3:´+13109 +  ´Nome: ´ + Cli1.nome + 13109 + ´Email: ´ + Cli1.email);
    PrintResp(´---------------------------------------´);
    PrintResp(´´);

    TesteCli4(@Cli1);
    PrintResp(´Externamente Cli4:´+#13109 +  ´Nome: ´ + Cli1.nome + 13109 + ´Email: ´ + Cli1.email);
    PrintResp(´---------------------------------------´);
    PrintResp(´´);

    TesteCli5(Cli1);
    PrintResp(´Externamente Cli5:´+13109 +  ´Nome: ´ + Cli1.nome + 13109 + ´Email: ´ + Cli1.email);
    PrintResp(´---------------------------------------´);
    PrintResp(´´);


end;



procedure TForm1.PrintResp(resp: string);
begin
    Memo1.Lines.Add(resp);
end;

procedure TForm1.TesteCli1(x: TCliente);
begin
    PrintResp(´***Por Valor***´);
    PrintResp(´Antes Cli1:´ +13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
    x.nome := x.nome + ´ Rubio ´;
    x.email := x.email + ´; vitorrubio@gmail.com´;
    PrintResp(´Depois Cli1:´ +#13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
end;

procedure TForm1.TesteCli2(var x: TCliente);
begin
    PrintResp(´***Por Referência (var)***´);
    PrintResp(´Antes Cli2:´ +13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
    x.nome := x.nome + ´ Rubio ´;
    x.email := x.email + ´; vitorrubio@gmail.com´;
    PrintResp(´Depois Cli2:´ +13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
end;

procedure TForm1.TesteCli3(out x: TCliente);
begin
    PrintResp(´***Por Referência (out)***´);
    PrintResp(´Antes Cli3:´ +13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
    x.nome := x.nome + ´ Rubio ´;
    x.email := x.email + ´; vitorrubio@gmail.com´;
    PrintResp(´Depois Cli3:´ +13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
end;

procedure TForm1.TesteCli4(x: PCliente);
begin
    PrintResp(´***Por Referência (ponteiro)***´);
    PrintResp(´Antes Cli4:´ +#13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
    x^.nome := x^.nome + ´ Rubio ´;
    x^.email := x^.email + ´; vitorrubio@gmail.com´;
    PrintResp(´Depois Cli4:´ +13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
end;

procedure TForm1.TesteCli5(const x: TCliente);
begin
    //não pode mudar
    PrintResp(´***Por Constante***´);
    PrintResp(´Antes Cli5:´ +13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
    //x.nome := x.nome + ´ Rubio ´;
    //x.email := x.email + ´; vitorrubio@gmail.com´;
    PrintResp(´Depois Cli5:´ +13109 +  ´Nome: ´ + x.nome + 13109 + ´Email: ´ + x.email);
end;

end.



GOSTEI 0
Cd.beco_df

Cd.beco_df

25/07/2007

ha uma diferença enorme entre o var e out,
o var - variavel de entrada
e out - variavel de sáida
outro dia precisei ter um retorno em uma variavel, no create de uma classe, mas como se sabe, um create nao é um metodo que tenha retorno, qual então o meu processo para que tenha sucesso, foi criar uma entrada Out para que retornasse o valor apos a criaçao da classe, o out funciona como o result de uma function.

vou demonstrar um simples exemplo aqui...

procedure TForm1.Processa(var V1,v2 : integer; out R :integer);
begin
R:= V1 + V2;
end

viu que OUt é o Retorno, ou variavel de saida?


GOSTEI 0
Vitor Rubio

Vitor Rubio

25/07/2007

essa diferença teorica eu conheço, mas na pratica, todo esse código que eu criei foi só para exemplificar, vc chegou a ver?

seguinte, use esse seu mesmo exemplo, mas passando var no lugar e out. Você vai peceber que o resultado é o mesmo e funciona da mesma maneira.

extendi o meu exemplo e o que eu descobri:
se você passar strings ou records coom out, no inicio da procedure esses valores são inicializados como vazios, mas se você passar integers, ou records que contenham integers, os integers não vão ser inicializados com 0.

Ou seja, se o objetivo é passar parametros do tipo integer, out tem o mesmissimo efeito de var. Seria um bug?

pode testar

procedure TForm1.Processa(var V1,v2 : integer; var R :integer); 
begin 
R:= V1 + V2; 
end 


duvido que não funcione


GOSTEI 0
Rjun

Rjun

25/07/2007

E qual o problema disso?


GOSTEI 0
Vitor Rubio

Vitor Rubio

25/07/2007

não é bem um problema.

É que, pela teoria, parametros out deveriam ser sempre inicializados automaticamente no inicio da rotina, descartando-se o seu valor inicial, não importa a linguagem que de suporte a isso. Isso acontece no delphi com todos os tipos de dados menos com integer, que é tratado o valor inicial igual se tivesse passato com o var.

eu tenho um repositório/coleção de exemplos onde eu coloco varios exemplos comentados e com arquivo readme.txt explicando pra que serve.

Simplesmente, usando integer para fazer o programinha de soma basico e classico e assim colocar esse exemplo no meu repositorio, eu simplesmente não consegui demonstrar o que eu queria: que o var usa o valor inicial enquanto que o out descarta-o, inicializando a variavel com 0;

Valew!


GOSTEI 0
POSTAR