20 de out. de 2011

Todo mundo quer uma API extensível

Como programador Java mas entusiasta de novas linguagens, acabo por sentir falta de alguns recursos que facilitam muito o trabalho, ou que pelo menos para mim fazem mais sentido usar.

Posso começar com um estudo de caso simples: dada uma String retornar o número de palavras.

É assim mesmo, simples assim, inclusive muito fácil de implementar em qualquer linguagem, mas a questão não é essa, como desenvolvedor eu quero usar orientação a objetos no projeto.

Vamos a uma implementação tosca em Java:
String frase = "Uma frase  de   exemplo";
System.out.println(frase.trim().split("\\s+").length);
Deu. Mostra 4. Entretanto eu quero reutilizar esta funcionalidade então em componentizo, bem, mas como?

Posso usar outro estudo de caso para dramatizar mais a história: verificar se uma String está em branco, ou seja, semelhante ao vazio só que ignorando espaços.

A implementação é medíocre:
String texto = "    ";
if (texto.trim().length() == 0) {
    System.out.println("vazio");
}
Não obstante, como no primeiro caso, eu quero componentizar.

No Java, é clássico fazer uma classe utilitária, algo como TipoUtils, neste caso, StringUtils:
public class StringUtils {
    public static int words(String str) {
        return str.trim().split("\\s+").length;
    }

    public static boolean isBlank(String str) {
        return str.trim().length() == 0;
    }
}
E uso assim:
String texto = "    ";
if (StringUtils.isBlank(texto)) {
    System.out.println("vazio");
}
Ainda posso usar um recurso introduzido no Java 5, o import estático.
import static meu.framework.utils.StringUtils.*;
// algumas linhas abaixo
String texto = "    ";
if (isBlank(texto)) {
    System.out.println("vazio");
}
Qual o problema com esta implementação? É que ela soa totalmente procedural em contraste ao modelo OO escolhido, em outras palavras eu queria fazer isso:
String texto = "    ";
// quero o próprio objeto me diga se está em branco
if (texto.isBlank()) {
    System.out.println("vazio");
} else {
     // quero que o próprio objeto me diga quantas palavras tem
    System.out.println("Existem " + texto.words() + " palavra(s)");
}
Em Java, impossível. No Java a classe String é final, ou seja, não pode ser estendida.

Para constar, uma extensão da API base do Java já existe e é distribuída pelo projeto commons do Apache e uma classe StringUtils já existe para estender as funcionalidades relacionadas a Strings e é muito bem escrita.

Mas isso não me deixa contente por que outras linguagens lidam muito melhor com esta situação, dando melhor suporte para estender a API base.

Vamos ao mesmo exemplo usando C#. No C# é possível, de certo modo, estender qualquer classe, mesmo as finais (sealed em C#), usando somente a API pública da classe, que já é suficiente para realizar muitas proezas:
public static class StringUtils {
 public static int Words(this string str) {
  return Regex.Split(str.Trim(), "\\s+").Length;
 }
 public static bool IsBlank(this string str) {
  return str.Trim().Length == 0;
 }
}
Implementações de classes estáticas no C# permitem estender a funcionalidade qualquer classe. Na verdade é um açúcar sintático no qual ele passa o conteúdo da variável para o método estático, ainda sendo procedural, mas de melhor leitura e mais elegante que em Java. Eu posso chamá-lo assim:
string texto = "    ";
if (texto.IsBlank()) {
    Console.WriteLine("vazio");
} else {
    Console.WriteLine("Existem " + texto.Words() + " palavra(s)");
}
Bem mais OO não acha? Pode ficar ainda melhor em Ruby, onde as classes são abertas. Em outras palavras, é possível estender a funcionalidade até mesmo das classes básicas como String e FixNum (inteiros). Claro que esta liberdade deve ser usada com parcimônia, é bem mais fácil fazer caca, mas com responsabilidade dá para fazer isso:
class String
    def words
        self.split.length
    end
    def blank?
        self.strip.length == 0
    end
end
Então eu posso usar estes métodos assim:
texto = "uma frase"
print texto.words
print "vazio" if texto.blank?
Sinceramente, sinto falta dessa flexibilidade em Java.

Acho exagerado a recomendação do Pragmatic Programmers de que todo programador deveria aprender uma linguagem por ano, por outro lado entendo o motivo que é propiciar novas visões, pontos de vista, ser mais crítico ao seu código, saber que há alternativas para fazer, melhor ou pior, aquilo que tu já faz todo o dia.

18 de out. de 2011

O operador 'Elvis'

O açúcar não deve ser consumido em excesso e nem deixar de ser consumido, assim como o sal, a gordura, etc.
Não, não virei nutricionista. É que este post é para falar de açúcar sintático, syntactic sugar em inglês, que é, em poucas palavras, o uso de operadores e construções da linguagem reduzem a escrita de um código maior e, assim como tudo, não pode deixar de existir na linguagens modernas e ao mesmo tempo não deve ser exagerado.

Nem sempre o açúcar sintático simplifica, pois às vezes tornam a leitura mais difícil, mas por outro lado economizam tempo -e tempo é dinheiro.

Vou citar um exemplo clássico, o operador ternário "? :"
Quem aqui né amigo não teve que escrever um código assim:
if (atraso > 10) {
    multa = 12.4;
} else {
    multa = 0.0;
}
Embora o código esteja em Java a construção é inerente a qualquer linguagem.

O mesmo código pode ser escrito usando o operador ternário, que é um açúcar sintático pois na prática ele compila, ou interpreta, para o código acima. Exemplo:
multa = atraso > 10 ? 12.4 : 0.0;
As linguagens estão cada vez mais adicionando açúcar sintático e uma que simpatizo muito é Ruby, entretanto como desenvolvedor Java sinto falta de um especialmente: o operador Elvis!

O "Elvis" -não me pergunte por que chamam assim, só sei o que dizem: "Elvis não morreu"- é uma simplificação do operador ternário para verificação de nulos. Por exemplo, imagine que desejes atribuir o valor de um parâmetro a uma variável, entretanto caso este parâmetro seja nulo é necessário atribuir um valor padrão. Vou propor um estudo de caso e uma implementação fictícia no código abaixo usando o clássico "if":
if (param.get("action") != null) {
    acao = param.get("action");
} else {
    acao = "listar";
}
O mesmo código poderia ser escrito assim:
acao = param.get("action") != null ? param.get("action") : "listar";

Esta sintaxe com operador ternário simplifica bastante porém ainda é possível simplificar ainda mais usando, bem, o Elvis! Abaixo uma implementação fictícia usando C#:
acao = param["action"] ?? "listar";
Bem melhor não concorda?
Java está meio atrasado nesta corrida por facilitação de sintaxe, o operador Elvis estava previsto para ser inserido no Java 7 e não rolou. A princípio ele teria a mesma sintaxe do Groovy, assim:
acao = param.get("action") ?: "listar";
Em Ruby ele é diferente sendo assim:
acao = param[:action] || "listar"
E pior, atualmente até o PHP tem, a partir da versão 5.3.

Enfim, o Java mostra sinais de idade e espero sinceramente que a Oracle com o Java 8 adicione mais liberdade a linguagem sem perder a elegância, a tipagem forte e robustez que o Java tem.