O const
é útil para um parâmetro ou somente para nerds e críticos?
Deveria ser: procedure Check(const Text: string);
? Ou é procedure Check(Text: string);
basicamente o mesmo?
Talvez você nunca tenha se perguntado como o compilador lida com seu código. E que efeitos isso tem em seu aplicativo. Mas se você souber um pouco sobre como isso funciona em segundo plano, é muito inteligente levar isso a sério. Isso é realmente importante para o desempenho e o tamanho do seu aplicativo.
Um parâmetro constante permite que o compilador associe o valor diretamente à variável, sem precisar reavaliá-la. Isso é chamado de constant propagation. Isso é (geralmente) combinado com uma técnica chamada constante folding . Em termos muito simples, o compilador garante que as variáveis sejam substituídas (durante a compilação) por expressões constantes, de modo que não precisem mais ser avaliadas em tempo de execução. Isso significa que o compilador já pode simplificar seu código e reduzir a quantidade de avaliações em tempo de execução. E, como resultado, ele simplesmente se torna mais rápido.
Há uma exceção, que são os parâmetros que já funcionam por referência, como é o caso dos objetos. Isso já está otimizado. Uma pequena exceção a isso é quando você trabalha com interfaces. Ainda há uma pequena diferença se você trabalha com ou sem const.
Depois de saber disso, você também poderá agir intencionalmente com isso. E se o fizer, não pense apenas em adicionar uma constante, mas pense também (por exemplo) no código em um loop que usa variáveis. O que acontece se você converter o conteúdo de um loop em um procedimento ou função com parâmetros constantes? Como você pode imaginar, isso tem efeitos positivos no desempenho. E esse é apenas um exemplo.
Pessoalmente, eu sabia que const era uma otimização do compilador, mas não sabia exatamente como funcionava. O gatilho para dar uma olhada mais de perto nisso veio de outro exemplo. Encontrei esse exemplo no fórum do MVP. É um ótimo exemplo que mostra que, em geral, você não está ciente do efeito no compilador. Você também pode tirar proveito disso, pois não se trata de uma construção incomum.
O exemplo é o seguinte:
function GetUserCollection: TUserCollection; begin if FUserCollection = nil then FUserCollection := TUserCollection.Create; Result := FUserCollection; end;
Esse código pode ser aprimorado para o compilador movendo o Create para outro método, como este:
function GetUserCollection: TUserCollection; begin if FUserCollection = nil then InitUserCollection; Result := FUserCollection; end; procedure InitUserCollection; begin FUserCollection := TUserCollection.Create; end;
Na primeira situação, o compilador leva em conta que, em cada chamada para GetUserCollection, é possível que um objeto precise ser criado. Os chamados registros de ativação são preparados para essa finalidade. Isso representa uma sobrecarga considerável, especialmente se você chamar essa função em um loop. Ao contrário do código otimizado, em que o compilador só precisa levar em conta a chamada a um procedimento.
No fórum MVP, isso foi medido e cada chamada no código otimizado foi executada com a mesma rapidez. O código não otimizado ficou cada vez mais lento. Já com 20 chamadas, levava quatro vezes mais tempo para chamar o procedimento. O atraso aumentou linearmente, tornando-se mais significativo a cada chamada adicional.
Esse exemplo e a variável const são dois exemplos de como sua maneira de codificar afeta o que o compilador pode ou não otimizar. Com desempenho pior ou melhor no final.
Contato