Introdução: por que comparar Rust e Haskell?
\n\nSe você já deu uma olhada no Stack Overflow em busca de uma resposta para a pergunta "What is the difference between traits in Rust and typeclasses in Haskell?", então sabe: o assunto é polêmico. Milhares de visualizações, dezenas de votos — a comunidade de desenvolvedores realmente quer entender como esses dois mecanismos diferem.
\n\nÀ primeira vista, eles são parecidos como irmãos: tanto traits em Rust quanto typeclasses em Haskell permitem definir um comportamento comum para diferentes tipos. Mas se você cavar mais fundo, descobre-se que a filosofia, a implementação e a aplicação prática deles são universos diferentes.
\n\nNeste artigo, analisaremos as principais diferenças com exemplos reais de código em Rust (com alguns toques de Haskell para contraste), e no final você terá uma compreensão clara: quando usar traits e onde é melhor pensar em uma abordagem semelhante a typeclass.
\n\nBreve visão geral: o que são traits em Rust?
\n\nTraits em Rust são uma forma de declarar um conjunto de métodos que devem ser implementados para um determinado tipo. Esta é a base da programação genérica (generics) e do polimorfismo em Rust.
\n\nUm exemplo simples: imagine que queremos que diferentes tipos saibam "cumprimentar".
\n\ntrait Greeter {\n fn greet(&self) -> String;\n}\n\nstruct Person {\n name: String,\n}\n\nimpl Greeter for Person {\n fn greet(&self) -> String {\n format!("Olá, meu nome é {}!", self.name)\n }\n}\n\nstruct Robot {\n model: String,\n}\n\nimpl Greeter for Robot {\n fn greet(&self) -> String {\n format!("Beep-boop, modelo: {}", self.model)\n }\n}\n\nfn say_hello(item: &impl Greeter) {\n println!("{}", item.greet());\n}\n\nfn main() {\n let person = Person { name: "Ana".into() };\n let robot = Robot { model: "R2-D2".into() };\n say_hello(&person);\n say_hello(&robot);\n}\n\nAqui, Greeter é uma trait. Os tipos Person e Robot a implementam de sua própria maneira. A função say_hello aceita qualquer tipo que implemente Greeter. Isso é o polimorfismo através de traits.
Breve visão geral: o que são typeclasses em Haskell?
\n\nTypeclass em Haskell é uma interface que define um conjunto de funções que podem ser implementadas para diferentes tipos. Parece familiar, certo?
\n\nAqui está como seria um exemplo análogo em Haskell:
\n\nclass Greeter a where\n greet :: a -> String\n\ndata Person = Person { name :: String }\ndata Robot = Robot { model :: String }\n\ninstance Greeter Person where\n greet (Person n) = "Olá, meu nome é " ++ n ++ "!"\n\ninstance Greeter Robot where\n greet (Robot m) = "Beep-boop, modelo: " ++ m\n\nsayHello :: Greeter a => a -> IO ()\nsayHello item = putStrLn (greet item)\n\nmain = do\n sayHello (Person "Ana")\n sayHello (Robot "R2-D2")\n\nA sintaxe é diferente, mas a lógica é a mesma. E ainda assim, as diferenças entre traits em Rust e typeclasses em Haskell começam exatamente aqui.
\n\nDiferença chave nº1: Monomorfização vs boxing (Box)
\n\nA diferença mais fundamental entre traits e typeclasses está em como o compilador lida com código genérico.
\n\nRust: monomorfização
\n\nQuando você escreve fn say_hello(item: &impl Greeter), o compilador Rust cria uma cópia separada da função para cada tipo específico. Isso é chamado de monomorfização. O resultado: abstração de custo zero (zero-cost abstraction) — você não paga pelo que não usa. Mas o tamanho do código pode aumentar.
Haskell: boxing (por padrão)
\n\nEm Haskell, typeclasses são geralmente implementadas através de dicionários de métodos (vtable). O compilador passa um parâmetro implícito — uma tabela com ponteiros para funções. Isso é chamado de boxing. Você paga pelo co