Beleza booleana
Até há muito pouco tempo atrás, expressões booleanas para mim eram apenas uma questão de verdadeiro ou falso, ifs, whiles e do..whiles. Nesta época, eu ria quando encontrava trechos de códigosdo estilo
boolean b = true; if (b == true){...}.
A vida era simples, linda e limitada.
Daí eu comecei a brincar seriamente com javascript e python, e descobri que existe muito mais coisas entre o céu e as funções booleanas do que poderia sonhar minha vã filosofia. Neste mundo novo, expressões booleanas podem ser muito mais do que apenas true ou false: elas podem ser formas extremamente elegantes e compactas para atribuição de valores.
Vamos por partes. Em Java, apenas variáveis do tipo booleanas ou expressões que retornem variáveis do tipo booleanas (maior que, menor que, igual a, contém, …) podem ser utilizadas em expressões booleanas. Uma construção do tipo if(1) não funciona.
Em linguagens de script, qualquer objeto pode ser avaliado como uma expressão booleana. Em Python por exemplo, a seguinte regra é aplicada: valores False (booleano), 0, “”, e None (valor nulo) são avaliados como falso; qualquer outro valor é avaliado como verdadeiro. A expressão (1 and 2) seria avaliada como true por exemplo.
Um outro ponto interessante em Python e Javascript é que expressões booleanas não retornam simplesmente True ou False: elas retornam o valor de um dos objetos da expressão. Uma expressão com AND retorna o último valor da expressão caso todos elementos sejam avaliados como verdadeiros, ou retorna o primeiro valor que fez com que toda a expressão fosse avaliada como falsa. Por exemplo: 1 and "miguel" and 2 retorna 2, porque todos os elementos da expressão são verdadeiros, e portanto a expressão toda é verdadeira. Já 1 and 0 and 2 retorna 0, uma vez que este é o primeiro elemento avaliado como false. E como todos sabemos, se um elemento é falso, a expressão toda é falsa.
No caso de uma expressão OR, ela retorna o primeiro elemento que for avaliado como verdadeiro, ou o último elemento da expressão caso todos os anteriores sejam avaliados como falsos. Por exemplo (1 or 2) retorna 1, e (0 or "") retorna “”.
Ótimo. Então como podemos usar isso para escrever expressões compactas, úteis e elegantes? Eis algumas sugestões:
- Valor default para uma variável: OR pode ser usado para garantir que caso um parâmetro seja passado com valor nulo para uma função por exemplo, ele receba um valor default: var v = param || “default”
- Expressões ternárias: o uso de OR e AND pode criar uma função ternária em linguagens que não possuem esta construção (Python por exempl0): var v = (condicao AND valor1) OR valor 2

Miguel, Ótimo artigo. Como fã de Python, assim como de códigos elegantes, gostei bastante do uso que apontou para essa peculiaridade. Sobre código compacto ser bom ou ruim, minha tendência como programador mais-que-amador é achar que é bom, ao menos do ponto de vista didático. Sempre que encontro algum trecho que não faz sentido em primeira vista, e sou obrigado a pesquisar que raios aquela linha de código faz, acabo por aprender mais um pouquinho sobre a dita linguagem/técnica.
Legal saber que essas expressões retornavam valor além de true e false.
Sou fã do estilo compacto [se for apreciado com moderação], e
var v = param || “default”
é bem mais bonito que
var v = (param == null) ? param : “default”
que é como eu costumava fazer.
Valeu pela dica!
O chamado “compacto” descrito aqui para mim está mais para obfuscação de código,
E eu só uso, e uso com prazer, em scripts de uso pessoal ou temporários (do tipo que eu vou apagar depois de usar).
Em meio profissional procuro escrever da maneira mais legível possivel, mesmo que resulte em nomes de classes a lá Spring como
ClassPathXmlApplicationContext.O que eu classifico como um ótimo estilo e encorajo seu uso. É preciso ter em mente que uma linha de código é muito mais lida do que alterada, a legibilidade conta e muito, ainda mais dependendo do perfil/cultura da empresa onde se trabalha.
Bruno, concordo com você que uma linha é muito mais lida do que modificada. Mas mesmo assim mantenho que é tudo uma questão de prática e olho treinado.
Exemplo de mundo real: se você encontrar um código em Java do tipo if (!isBound()), vc de cara vai saber que isBound é uma função que retorna um booleano e que o if será executado caso o valor retornado pela funçao seja false. Correto?
Pois bem, quem ta se iniciando em programação talvez tenha dificuldade de entender. Eu me lembro quando capi em algo assim, lá em 1995 e fiquei um tempão pra entender.
E mesmo assim, andei me deparando com uns if (isBound() == false), cujo motivo alegado é legibilidade…
Eu acho o
(!isBound())bem legível até para iniciantes… Agora colocar o== false/trueeu acho uma besteira sem tamanho… É um estilo que me desagrada muito.E olho treinado também se cansa e deixa passar statements não óbvios o tempo todo, principalmente sob pressão e cansado, algo mais do que comum em nossa área.
Bruno, é engraçado como o que você usa como suporte para a argumentação viola a conclusão.
Se uma linguagem oferece uma construção com uma abstração maior (mais próxima da “linguagem humana” do que da “linguagem da máquina”) e se essa mesma construção permite que você tenha uma capacidade maior de expressar idéias em menos código, como é que você acaba por argumentar que um estilo que promove verbosidade e redundância de tokens ajuda na legibilidade?
Miguel,
Eu, particularmente, sou um fã moderado de estruturas que compactam o código. Acho que muitas vezes elas servem apenas para diminuir a legibilidade do código.
Por exemplo, para mim, o seu primeiro exemplo é fantástico e simples! Já o segundo é relativamente sofrível de entender, na minha opinião. Principalmente se você nunca viu um código, está tentando entendê-lo pela primeira vez e não tem muito tempo para isso. Algo que recorrentemente acontece durante um ciclo de desenvolvimento.
Coincidentemente estou tendo uma discussão muito parecida com esta no meu trabalho nos últimos tempos. O engraçado é que, como já escrevi aqui algumas outras vezes, todo o meu desenvolvimento é de plug-ins para Eclipse, ou seja, Java. Java, como C, tem algumas construções de código que podem torná-lo menor mas que por outro lado, podem torná-lo mais ilegível também. Resta saber qual é esta linha entre compacto/ilegível para a sua equipe de desenvolvimento.
No nosso caso estamos usando o próprio Eclipse para definir os padrões que queremos seguir. O IDE permite que você selecione níveis de avisos para construções sintáticas que, apesar de não estarem erradas pela especificação da linguagem, podem causar confusão para um leitor desavisado ou mesmo bugs por desatenção do programador. Um exemplo clássico sob o qual é possível setar o nível de aviso é o uso de “switch case fall-through”, ou seja, quando você dentro de um case de um switch não utiliza um break e força a continuação da execução do código do próximo case para o case anterior também. Apesar de permitido pela linguagem, isso pode causar confusão para um leitor desavisado do seu código e, pior, pode ser uma fonte de bugs já que na maior parte das vezes você vai querer colocar um break em cada case do seu switch.
Enfim, como eu disse antes, algo que eu acho que deve ser usado com cuidado. Muito cuidado. E com o consentimento de sua equipe de desenvolvimento como um todo.
Agora… se estivermos falando de código próprio… Bom, eu uso e abuso de compactações de código. Afinal, eu acho que é uma ótima oportunidade de aprender e só eu mesmo vou ler o que eu estou fazendo.
Leo,
eu acho que existe algo que tem que ser levado em conta nisso tudo: bom senso. Eu já devo ter dito isso em algum lugar neste blog, mas vale a pena ressaltar: eu tenho cada vez mais certeza de que escrever código é uma arte. Muito semelhante a escrever texto. Quando escrevemos um texto, o estilo depende muito da finalidade. As vezes queremos um texto mais direto, seco. Outras vezes, um texto mais poético. As vezes mais cínico. O mesmo vale pra código: as vezes queremos um código mais enxuto, as vezes queremos um código mais explícito e óbvio. Mas eu acredito que é importante que desenvolvedores fiquem sempre atentos a novas formas de efetuar certas tarefas, novos recursos…..é importante ter o maior número de ferramentas na nossa caixinha de maldades. As expressões booleanas que eu mencionei no texto são algumas destas ferramentas.
Quanto à questão da legibilidade, eu mantenho o que eu disse antes: quanto mais treinado for o olho, mais legível será o código. E sinceramente, acho que a qualidade não deve ser nivelada pelo nível do pior programador da equipe. Pelo contrário: quanto maior o nível do código, maior vai ser o progresso dos membros.
E vale ressaltar que a quantidade de código medíocre por aí, feito sem nenhum tipo de interesse ou cuidado, é enorme. Não que eu ache que os meus códigos sejam geniais. Pelo contrário. Mas eu tenho uma autocrítica extremamente alta, e tento o tempo todo descobrir coisas novas e melhorar.
[]s
E gostaria de fazer um adendo um tanto quanto provocativo.
Acho que hoje em dia os desenvolvedores se preocupam muito com arquiteturas de classes, heranças, patterns e afins, e se preocupam muito pouco com a qualidade do código que vai dentro dos métodos.
E é fato que uma expressão do tipo (v AND 1) or 2 pode ser bem dificil de entender a primeira vista. Mas não é mais dificil do que tentar entender um método que chama um façade que chama um proxy que chama uma interface cuja implementação é injetada por uma lib cuja definição está num XML perdido em algum lugar da arvores de arquivos de properties do sistema. Que jogue uma pedra aquele que nunca passou alguns minutos apertando Ctrl Mouse no Eclipse para tentar encontrar onde raios estava a implementação de um método.
Mas isto é assunto prum outro post….
Raphael, um if retornar algum dos operandos da expressão booleana está anos luz longe da linguagem “humana”.
“Mais idéias em menos código” nem sempre leva a uma perda de legibilidade, me vem em mente agora os operadores para “fatiar” strings de Ruby por exemplo, onde o código fica menor e ainda sim fácil de ler.
Mas muitos estilos de codificação mais compactos levam sim a uma perda enorme de legibilidade do código lhe forçando a gastar muitas vezes mais tempo para ler uma linha que de outra maneira poderia ser compreendida apenas “batendo o olho”. E lembrando que no nosso dia a dia nós lemos milhares de linhas de código e mtas vezes estamos em condições de stress onde pequenos detalhes “escapam” para o ambiente de produção impunemente, graças mtas vezes a erros de leitura…
O estilo que eu defendo de maneira alguma promove a redundãncia de tokens, baseado em que você assumiu isto??? Algum exemplo que eu citei aqui???
Em meio profissional procuro escrever da maneira mais legível possivel, mesmo que resulte em nomes de classes a lá Spring como ClassPathXmlApplicationContext.
Em quantos lugares diferentes passam declarações de classes, arquivos XML para fluxo do programa, configuração e instanciação e etc? Vários. Redundância “extreme”.
Raphael, Primeiro, o nome
ClassPathXmlApplicationContexté um token só.O funcionamento interno de um container (como por exemplo o do Spring) em nada está relacionado com uma conversa sobre a sintaxe de uma linguagem ou certo estilo de programação ser verborrágico ou não, compreende a diferença?
Right. My Bad. I’m too stupid. Sorry for that.
Miguel, mesmo assim ainda prefiro esse estilo de varreduras de classes e métodos no Eclipse, pois às vezes bater o olho na especificação do método (aka contrato) já me basta, se eu estiver interessado apenas no “o que” o método faz e não “como”.
Com relação à questão de “quanto mais treinado, mais legível o código”, ainda assim prefiro ter um método ou função com um nome legível informando a responsabilidade da operação, do que poucas invocações compactas que retornem booleanos e determinem resultados de validações / verificações. Na tarefa de simples “bater o olho”, é rápido de se afirmar o que faz determinado método. Por exemplo, eu prefiro muito mais um isCreditCardAuthorized() do que linhas dispersas retornando booleanos que resumem esta operação. A manutenção se torna em muito facilitada.
Rafael,
1) eu nao advoguei em nenhum momento no texto o NÃO uso de nomes claros e explicitos em funções, variáveis e estruturas de dados. Pode procurar, eu tenho certeza disse. Eu faei da vantagem de ter EXPRESSÔES COMPATCTAS, com grande poder. Eu DETESTO funçoes com nomes do tipo fddq, ou variáveis c, h e a (a menos que sejam temporarias e bem localizadas).
2) Eu tampouco critiquei a funcionalidade do Eclipse de varrer código. Acho isso muito útil e uso demais. EU critiquei estruturas extremamente complexas (em geral criadas em nome de uma certa escalabilidade) que fazem com que qualquer código tenha no mínimo dois níveis de indireção.