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.
Introdução à variáveis inline
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:
1 2 3 4 5 6 |
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:
1 2 3 4 5 |
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:
1 2 3 4 5 6 7 8 9 10 11 |
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:
1 2 3 4 5 6 7 8 |
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:
1 2 3 4 5 |
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.
Variáveis inline em loops
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:
1 2 3 4 5 6 7 8 |
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; |
Conclusão
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! 🙂
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”.
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!
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.
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!
Legal!
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?
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:
Abraço!
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:
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?
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!
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.
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!
Este with é um tiro no pé.
Muito Legal!
Boa noite André, tudo bem?
Seguinte, estou utilizando uma variável inline, mas ao utilizar um objeto dentro de um try/finally eu coloco um FreeAndNil() do objeto após executar o código e tryf não consegue identificar a variável. Em paralelo a isso eu coloquei o FreeAndNil() no final do código mesmo.
Como poderia está trabalhando melhor com esse tipo de variável inline em um try/finally?
Olá, Elton, como vai?
Variáveis inline podem ser referenciadas apenas dentro do escopo na qual foram declaradas. Portanto, para utilizá-las em uma estrutura try/finally, essa seria a melhor opção:
Espero ter respondido a sua dúvida. Abraço!
Obrigado Celestino, realmente eu tinha feito o teste com o try/finally e try/exception para tratamento do erro e por isso não tinha dado certo. Então resolvido deixar a variável no formato padrão antes do inÃcio do procedimento.
Certo, Elton!
Só reforçando que a variável não precisa ser declarada necessariamente antes do inÃcio do procedimento. Você pode declará-la antes de iniciar o bloco try/finally. 😉
Abraço!
Olá André,
Aqui meu post publicado no Idera Community para tentar explicar um pouco do “var inline”:
https://community.idera.com/developer-tools/programming-languages/f/delphi-language/69490/inline-variable-declaration-works-if-used-correctly
Olá!
Obrigado pela contribuição! O código ficou muito bom 🙂
Fiz questão de vir aqui agradecer, depois de andar as cegas pela internet até que enfim alguém que ensina de forma objetiva e sem rodeios. Muito Obrigado.
Olá, Cláudio!
Muito obrigado pelo feedback!
Grande abraço!
A sintaxe correta seria esta:
procedure TForm1.SpeedButton1Click(Sender: TObject);
Procedure ShowItems(List:TStringList);
begin
ShowMessage( List.Text );
end;
begin
var List : TStringList := TStringList.Create;
with (List) do
begin
Add(‘Item #1’);
Add(‘Item #2’);
ShowItems(list);
Free;
end;
end;
Entendo sim que poderia ser dentro do with, quem sabe em um futuro breve, já que a VCL esta sendo atualizada a quase 30 anos.
Olá, Eduardo.
Não sei qual versão você testou esse código, mas no Delphi 12 funcionou perfeitamente.
Abraço!