Programação Funcional: o que são objetos de primeira classe?

Photo by Min An from Pexels

Java foi a primeira linguagem de programação que aprendi e na qual comecei a programar profissionalmente. Sendo assim, por muito tempo fiquei bem apegado a “forma Java” de pensar sobre código. Porém, a medida que você começa a observar o JavaScript e conceitos de programação funcional, começa a ficar muito claro que Java e JavaScript vivem em mundos bem diferentes, especialmente no que se refere a forma de tratar as funções.

Tanto no Java quanto no JavaScript, funções são objetos. No Java, esses objetos aparecem apenas dentro de classes, e portanto são chamados de métodos. É perfeitamente comum vermos declarações de métodos da seguinte forma:

public class Pessoa {
     String nome;
     int idade;

     constructor(String nome, int idade){
         this.nome = nome;
         this.idade = idade;
     }

     public String getNome() {
         return this.nome;
     }

     public String getIdade() {
         return this.idade;
     }

     public void printInfo() {
         System.out.println(getNome() + ", " + getIdade());
     }
 }

//em outra classe
Pessoa p = new Pessoa("Jon Snow", "33");

Os métodos existem sem maiores problemas dentro das classes. Mas se eles são objetos, por que não podemos armazená-los em variáveis, assim como acontece com o tipo Pessoa? Caso tentássemos fazer algo assim com Java, provavelmente escreveríamos mais ou menos assim:

Method printInfo = public String printInfo() { … };
printInfo();

Se você já programou em Java, sabe que o código acima não funciona. A linguagem não nos permite colocar um método dentro de uma variável (apesar de possuir um tipo Method, que não serve para esse tipo de situação). Contudo, algo assim é perfeitamente razoável em JavaScript:

var printInfo = function printInfo() {
     console.log("info");
 };
 printInfo();

Mas, o que permite que isso seja possível? Por que no JavaScript uma função pode ser armazenada em uma variável e no Java não podemos fazer o mesmo com um método? Bom, isso tem a ver com a forma como cada linguagem trata as funções. No JavaScript, as funções são objetos de primeira classe (também conhecidos pelo termo “cidadãos” de primeira classe), ou seja, eles tem os mesmos “poderes” que todos os outros objetos tem: podem ser armazenadas em variáveis, retornadas por outras funções (também chamadas de funções de alta ordem), passadas como parâmetros, etc. Em Java, as funções são objetos de segunda classe, ou seja, têm “poderes” mais limitados.

Mas, afinal, qual é a melhor forma de tratar as funções? Analisando os exemplos acima, fica evidente que tratando as funções como objetos de primeira classe, temos muito mais flexibilidade para lidar com elas. Podemos criá-las e chamá-las quando bem desejarmos, sem precisar de uma estrutura de classes, e podemos combiná-las de diferentes formas para realizar operações. Porém, será que existe alguma vantagem em “puxar o freio” e considerar as funções como objetos de segunda classe, assim como faz o Java?

Eu diria que talvez a única vantagem seja colocar um pouco mais de ordem no caos. Em uma linguagem fracamente tipada como o JavaScript, é impossível assegurar que uma variável irá permanecer com dados do mesmo tipo por toda a execução do programa. Apesar de abrir espaço para eventuais erros e equívocos, essa situação não necessariamente reflete um problema na classificação das funções e sim um problema de tipagem. Sendo assim, tirando a dificuldade que isso eventualmente pode causar para quem cria linguagens (como o problema funarg), tratar as funções como objetos de primeira classe tem bem mais vantagens do que desvantagens.

Considerações finais: se você quer flexibilidade para trabalhar com funções, trate-as como objetos de primeira classe. Elas merecem essa honra 🙂

Fontes: