Quem veio primeiro: a classe Class ou a classe Object?

em Desenvolvimento, Ruby.

Outro dia eu estava lendo o livro “The Well-Grounded Rubyist” do David Black – que, aliás, é uma boa leitura para aprender desde o básico de Ruby até elementos mais avançados da linguagem – e um parágrafo específico me chamou a atenção (na tradução literal):

Tudo o que você manipula em Ruby ou é um objeto ou alguma estrutura que se resulta em um objeto e todo objeto é uma instância de alguma classe e classes também são objetos.

Eu li e reli várias vezes esse trecho e fiquei bastante tempo refletindo sobre como classes poderiam ser objetos. Como eu venho de Java foi difícil de conseguir imaginar como isso era possível, pois lá classes são especificações modeladas em tempo de compilação somente para que possamos construir objetos as utilizando em tempo de execução. Não há objetos até  que você instancie uma classe.

Em Ruby isso também é verdade (tirando o fato de que não há tempo de compilação, pois um programa em Ruby não é compilado, mas sim executado), classes geralmente existem para que se possam ser criados objetos a partir dela. E foi esse fato que me deixou mais intrigado: uma vez que classes também são objetos e todos os objetos a princípio são originados por classes, então em que momento ou como essas classes são instanciadas?

Uma discussão quase filosófica

Para ajudar bastante nosso querido David fez as seguintes afirmações:

“A classe Class é uma instância dela mesma – isto é, ela é um objeto Class. E há mais ainda. Lembra-se da classe Object (classe que quase todas as classes herdam, eu costumo chamar de classe mãe)? Bem, Object é uma classe – mas classes são objetos. Então, Object é um objeto. E Class é uma classe. E Object é uma classe, e Class é um Objeto.

Toda vez que eu leio esse trecho de informação, só o que me vem a cabeça é que “Os carros são como as lanchas, as motos são como os jet-skis e os pedestres são como os banhistas!” (se você é dessa época vai entender a piada :D).

Realmente não é atoa que existe ai um paradóxo muito famoso que certamente você conhece: “Quem veio primeiro, o ovo ou a galinha?“. Se pararmos para pensar é exatamente dentro deste paradoxo que o David acabou de nos deixar: “Quem veio primeiro, a classe Class ou a classe Object?” Essa pergunta é muito difícil de responder quando analisamos o seguinte, muito bem colocado nessa resposta no stack overflow:

  1. Cada classe é uma instância da classe Class. Então segue que a classe Object é uma instância da classe Class. Então você precisa de uma classe Class para criar uma classe Object. Portanto a classe Class existe antes da classe Objeto.
  2. A classe Class é uma subclasse da classe Object. Então você precisa de uma classe Object da qual a classe Class pode ser criada. Portanto a classe Object existe antes da classe Class.

Essas duas afirmações só clarificam um pouco o que David falou em seu livro, mas deixa claro que há uma definição circular nesse contexto. Depois de perguntar para várias pessoas e pesquisar na internet, uma das explicações mais plausíveis que eu consegui achar foi a seguinte: existem dois tipos de objetos em Ruby, os que são built-in (não consegui achar uma palavra em português boa para traduzir esse termo) e os que são criados pelos usuários.

Os built-in são os que são iniciados quando programa é carregado e executado e os criados pelos usuários são os que vem depois. Essa explicação nos faz aceitar que existe algum mecanismo do Ruby no tempo zero de criação de seus inicializadores que faz com que toda essa mágica aconteça. Pesquisando bastante por ai eu não consegui achar uma explicação profunda de como isso é feito, somente um trecho resumido do próprio autor:

Cada objeto tem um registro interno de qual classe ele é uma instância, e o registro interno do objeto Class aponta de volta para ele mesmo.

Interessante, não? Apesar de não explicar detalhadamente como isso é feito, dá para perceber que realmente existem mecanismos na inicialização do programa que são responsáveis por fazer tais registros. E, uma vez que a class Class tem seu registro apontado para si mesma, entende-se que ela é inicializada primeiro que a class Object, que tem seu registro apontado para a class Class.

Mais do que entender como isso é feito, é preciso saber (ou aceitar!) que classes no Ruby também são objetos. Apesar de parecer uma discussão quase filosófica, ter conhecimento desse fato permite que você passe a compreender melhor algumas das funcionalidades da linguagem que talvez ainda não lhe faça sentido, como por exemplo a metaprogramação – muito bem explicada neste artigo do Guilherme Batista.

Você também pode gostar