domingo, 2 de junho de 2019

Ordem de testes

No outro dia me deparei com um código mais ou menos assim:

int f( bool a, int b, int c, int d )
{
  if( b > c && a == false )
    return 1 ;
  else if( c < d && a == false )
    return 2 ;
  else if( a == true )
    return 3 ;
  else
    return 4 ;
}


Olhem para ele e digam o que está errado, o que pode ser melhorado. Depois de pensar nele, cliquem em "Mais informações" para ver o resto da discussão.

Primeiro, tipo booleano, em qualquer linguagem de programação que eu conheço, não precisa ser comparado com true ou false.

int f( bool a, int b, int c, int d )
{
  if( b > c && !a )
    return 1 ;
  else if( c < d && !a )
    return 2 ;
  else if( a )
    return 3 ;
  else
    return 4 ;
}

Bons compiladores resolvem isto na boa, mas é meio deselegante fazer as comparações. Elas fogem do propósito.

Mas ainda tem algo mais estranho ainda. Observe o terceiro if. Se mudarmos a ordem simplifica os testes dos dois primeiros if's.

int f( bool a, int b, int c, int d )
{
  if( a )
    return 3 ;
  else if( b > c )
    return 1 ;
  else if( c < d )
    return 2 ;
  else
    return 4 ;
}

Agora sempre que a variável a for true o resultado logo estará determinado, e não será mais necessário testar esta variável.

Mesmo que esta condição pouco ocorra, ela era testada nos outros dois casos, então mudar a ordem elimina o teste nos outros dois casos. Para quem conhece como os códigos são gerados pelo compilador, sabe que expressões E e OU também geram códigos com jumps condicionais. No fundo, esta mudança ainda é capaz de dar uma boa simplificada no código gerado.

Mas em todas as situações temos um return. Então o else se torna redundante. O código abaixo tecnicamente é equivalente com o de cima.

int f( bool a, int b, int c, int d )
{
  if( a )
    return 3 ;
  if( b > c )
    return 1 ;
  if( c < d )
    return 2 ;
  return 4 ;
}

Então fique atento com as sequências de if's.

Um comentário:

  1. O Fernando Ferreira no Facebook propôs a seguinte solução, que é baseada na minha penúltima solução.

    return a ? 3 : ((b > c ? 1 : (c > d ? 2 : 4)));

    A solução dele é bem compacta de escrever, e pode basicamente o mesmo código, ou um radicalmente diferente usando uma variável temporária.

    ResponderExcluir