Avaliação booleana em modo "curto-circuito" e operandos do tipo Variant

Qualidade: 

Estrela ativaEstrela ativaEstrela ativaEstrela ativaEstrela ativa
 

O modo curto-circuito de avaliação boolena é a forma padrão de avaliação lógica de todas as linguagens de programação. Basicamente o curto-circuito é um conceito que prega que uma expressão booleana complexa seja avaliada o mais rapidamente possível pelo compilador mediante o descarte de avaliações adicionais que são óbvias ou nulas dentro da referida expressão.

Se ainda assim não consegue entender o que é uma avaliação boolean em curto-circuito, dê uma olhada em Boolean short-circuit evaluation (Delphi compiler directive) e saiba que mesmo sem você saber da existência disso, provavelmente você usa, pois o curto-circuito é padrão do Delphi.

Chega de bla bla bla. Tenho a seguinte função:

function CanSelect(const aTableName: String): Boolean;
begin
  Result := CurrentSession.Data.bo_superusuario 
         or CLDSPermissoes.Lookup('ENTIDADE',aTableName,'LER');
end;

A lógica é simples: A função vai retornar TRUE se eu for um superusuário ou se eu tiver permissão de leitura para a tabela passada no parâmetro aTableName.

Como a diretiva de compilação {$B-} está ativada como padrão, a lógica diz que se CurrentSession.Data.bo_superusuario for TRUE, o segundo operando nem mesmo vai ser avaliado pois apenas a condição do primeiro operando já é suficiente para saber o resultado da expressão booleana inteira. O que estava acontecendo é que o segundo operando, neste caso, estava sendo avaliado, mesmo quando o primeiro era TRUE, que, no meu caso gerava um exceção por conta de CLDSPermissoes estar inativo.

Após algumas pesquisas atentei para o fato do segundo operando (Lookup) retornar um dado Variant e por este motivo o compilador não tem condições de saber se ele é realmente um booleano ou não, causando a avaliação completa da expressão booleana mesmo no modo {$B-}. Ao meu ver isso é algum tipo de bug relacionado ao modo {$B-} o qual deveria "curtocircuitar" a expressão APENAS após a conversão do dado Variant, mas isso é outro assunto.

Após descobrir a causa do problema que impactava na minha lógica, foi simples resolver o problema. Simplesmente dei um cast no variant para Boolean, explicitando para o compilador que se trata de um operando BOOLEANO, assim:

function CanSelect(const aTableName: String): Boolean;
begin
  Result := CurrentSession.Data.bo_superusuario 
         or Boolean(CLDSPermissoes.Lookup('ENTIDADE',aTableName,'LER'));
end;

Desta forma a lógica funciona como deve. Fica a dica!

e-max.it: your social media marketing partner