[Delphi Rio] Uma grande novidade: declaração de variáveis inline

[Delphi Rio] Declaração de variáveis inline

Olá, pessoal!
Antes de iniciar a nova série de artigos, pretendo divulgar, aos poucos, algumas novidades do Delphi Rio, que será lançado em breve. Diga-se de passagem: são mudanças interessantes! Para iniciar, apresento-lhes um novo recurso na linguagem Delphi, que nos permite declarar uma variável em qualquer local do código.

 

A partir da versão 10.3 (Rio), será possível declarar uma variável após o bloco begin-end, ou seja, a declaração de variáveis na seção var não será mais obrigatória. Essa característica é chamada de inline, que, ao pé da letra, traduz-se como “na linha”.

Sendo assim, leitores, o código abaixo passa a ser válido:

procedure Exemplo1;
begin
  var Nome: string;
  Nome := 'André Celestino';
  ShowMessage(Nome);
end;

 

Além disso, este novo recurso de declaração também possibilita a inicialização de variáveis:

procedure Exemplo2;
begin
  var Idade: integer := 18;
  { ... }
end;

 

Variáveis declaradas dentro de um bloco de código só estarão disponíveis naquele escopo. Logo, uma variável declarada dentro de um bloco begin-end é limitada apenas à esse bloco, como no exemplo abaixo:

procedure Exemplo3;
begin
  if QtdeVendas > 0 then
  begin
    var TotalVenda: double;
    TotalVenda := ObterTotalVenda;
  end;
 
  // essa linha irá gerar um "Compile Error: Undeclared identifier: TotalVenda"
  ShowMessage(TotalVenda.ToString);
end

 

E o gerenciamento de memória?
Pois bem, variáveis de tipos de dados “gerenciados” pelo compilador (como strings, Interfaces e records) serão liberadas automaticamente ao término do escopo no qual elas foram declaradas. No exemplo a seguir, a variável do tipo de Interface é descartada após o begin-end:

procedure Exemplo4;
begin
  if UsarAPI then
  begin
    var API: IInterface = GetAPIInterface;
    API.AtualizarStatus;
  end; // neste "end", o método "Release" da Interface será chamado
end;

 

Outra novidade também deste recurso é a inferência de tipos. Ao omitir o tipo de dado de uma variável, o compilador irá inferir o tipo com base no valor que a variável recebeu:

procedure Exemplo5;
begin
  var Linha := 10; // compilador infere que é um tipo inteiro
  Inc(Linha); // resultado será 11
end;

No código acima, vale um adendo: o compilador irá usar o “maior tipo” mais próximo como dedução. Neste caso, a variável “Linha” será do tipo integer. Caso o desenvolvedor queira um tipo mais restrito, como shortint ou smallint, deverá declará-lo explicitamente.

 

Talvez, uma das maiores vantagens deste recurso de inline é a possibilidade de dispensar a declaração de variáveis que servem como contadores em estruturas for. Dessa forma, a variável poderá ser declarada na própria linha do for, lembrando, claro, que essa variável não estará disponível após o laço. Veja o exemplo:

procedure Exemplo6;
begin
  // indicando o tipo...
  for var Contador: integer := 0 to 10 do { ... }
 
  // ... ou simplesmente permitindo que o compilador faça a inferência
  for var Contador := 0 to 10 do { ... }
end;

 

Todos estes recursos dividiram a comunidade Delphi. Muitos gostaram, enquanto outros, não. Eu, particularmente, acredito que só temos a ganhar com a adição dessas novas features, desde que sejam utilizadas visando a qualidade do código.

Ao meu ver, essa nova feature da linguagem traz as seguintes vantagens:

  • Reduz a quantidade de variáveis na seção var, principalmente no caso de contadores em estruturas for;
  • Melhora a expressividade do código, uma vez que determinadas variáveis só serão declaradas e utilizadas dentro de um escopo específico;
  • Reduz linhas de código em função da inicialização de variáveis e inferência de tipos.

 

Porém, deixo também a minha recomendação: use este recurso com moderação! Em métodos complexos, várias variáveis espalhadas no código podem mais atrapalhar do que ajudar. Além disso, pense sempre em Clean Code. Escreva métodos pequenos para que a quantidade de variáveis não seja excessiva.

Para mais detalhes sobre inline variables, visite o blog do Marco Cantu:
http://blog.marcocantu.com/blog/2018-october-inline-variables-delphi.html

 

Volto logo, pessoal! 🙂


 

13 comentários

  1. Bom, não sei como a comunidade possa estar dividida neste tocante, aliás não li nenhum comentário negativo, ademais essas funcionalidades não são novas em linguagens seguras como Ada que usa uma sintaxe parecida incluso “Safe Type inference”.

    1. Olá, Marcelo!
      Alguns desenvolvedores da linguagem Delphi defendem que há outras melhorias mais importantes a serem adicionadas à linguagem, como o try/except/finally. Outros também se preocupam com Clean Code, visto que o uso “desenfreado” desse novo recurso pode comprometer a legibilidade e compreensão do código.
      No mais, boa parte da comunidade gostou do recurso e estão fazendo comentários bem positivos. 🙂

      Abraço!

    2. Eu não gostei, acho que ajuda a bagunçar o código. Coisas com MVC, desenvolvimento robusto para web, desejar o objeto não visuais com query com uma aba separada, algo parecido com linq, seriam mais úteis.

      O pessoal novamente perdendo o foco.

    3. Obrigado pelo comentário, Elter.
      Concordo que há uma série de melhorias bem importantes que poderiam ser exploradas pela Embarcadero. Vamos aguardar as próximas versões e esperar boas novidades.
      Abraço!

  2. Oi André!
    Tentei usar variáveis inline dentro de um block With e não consegui. Veja o exemplo abaixo. Será que a sintaxe tá errada ou o Delphi 10.3 não contemplou esse tipo de declaração no With .. Begin .. End?

    Procedure ShowItems(List:TStringList);
    Begin
       ShowMessage( List.Text );
    End;
    
    { Working fine }
    procedure TForm1.Button1Click(Sender: TObject);
    Var List : TStringList;
    begin
       List := TStringList.Create();
       With List do
       Begin
          Add('Item #1');
          Add('Item #2');
          ShowItems(list);
          Free;
       End;
    end;
    
    { compiler error }
    [dcc32 Error] E2018 Record, object or class type required
    procedure TForm1.Button2Click(Sender: TObject);
    begin
       With Var List : TStringList := TStringList.Create() do
       Begin
          Add('Item #1');
          Add('Item #2');
          ShowItems(list);
          Free;
       End;
    end;
    1. Olá, Breno, tudo bem?
      Ótima pergunta. O recurso de inline variables infelizmente não contempla a estrutura With. No entanto, analisando o seu código, você pode criar o objeto diretamente no With, dispensando a necessidade de uma variável:

      With TStringList.Create() do
      Begin
        Add('Item #1');
        Add('Item #2');
        ShowItems(list);
        Free;
      End;

      Abraço!

  3. André, obrigado pelo retorno. Mas veja que preciso da variável pra passar sua instância para a procedure ShowItems(????). Se eu criar dinamicamente não tenho nenhuma referência de objeto pra passar:

    With TStringList.Create() do
    Begin
      Add('Item #1');
      Add('Item #2');
      ShowItems(list);  *** preciso passar a referencia para outra rotina ***
      Free;
    End;

    Esse é apenas um exemplo ilustrativo, tenho rotinas mais complexas onde preciso “transportar” a instância pra outra rotinas.

    A sintaxe do With deveria ser similar a “using” do C#, não acha?

    using (MyClass mine = new MyClass())
    {
      DoSomething(mine);
      mine.Action();
    }
    1. Olá, Breno! Peço desculpas pela demora.
      Você tem razão. Ao criar o objeto da forma como apresentei no comentário anterior, não há referência para enviar como parâmetros em métodos. E pode parecer estranho, mas eu não conhecia essa possibilidade no C#, rsrs. Vamos torcer para que a Embarcadero complemente este recurso nas próximas versões.
      Obrigado pelo retorno, Breno. Abraço!

  4. Beleza cara, valeu!
    Eu já estava achando que eu não estava sabendo usar as variáveis inline do novo Delphi, mas pelo visto a Embarcadero não fez um trabalho completo. É uma pena, pois o With Do do Pascal é uma estrutura muito falha pra se trabalhar com uma instância inline de objeto. Além de não ter uma referencia “self” é muito suscetível a ambiguidade de referências quando usado em cascata com outros “With’s”, chegando ao ponto de muitos desenvolvedores considerarem uma má-prática de programação seu uso.

    1. Concordo, Breno.
      A estrutura With-Do, quando empregada de forma coerente, traz boas vantagens para o código. Eu, particularmente, não tenho o costume de usar Withs cascateados. Quando essa necessidade surge, prefiro partir para o Clean Code e extrair o segundo nível para um método isolado.
      De qualquer forma, vamos continuar acompanhando as próximas evoluções da linguagem Delphi!
      Abraço!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *