sexta-feira, 4 de setembro de 2009

Truques em Scala - Structural Typing

As linguagens dinâmicas como Ruby e Python tem algumas capacidades bem interessantes, entre elas esta a possibilidade de passar um objeto para um método e desde que o objeto implemente os métodos necessários (ex: name, height), o método executará corretamente.

Já as linguagens estáticas normalmente não tem essa capacidade, algumas, como por exemplo Boo implementam essa possibilidade através de dispatch in runtime para os métodos que necessitam dessa caracteristica, já Scala tem uma solução bem elegante.

Por exemplo, digamos que você queira definir um método que espere um objeto que tenha as propriedades name e age, uma forma comumente usada em linguagens estáticas seria a seguinte:

Definir uma interface com os métodos que interessam:

trait BasicProperties {
  def name: String
  def age: Int
}

Escrever as classes implementando BasicProperties e o método recebendo como parametro um objeto do tipo BasicProperties:

class Pet(val name: String, val age: Int) extends BasicProperties
class Person(val name: String, val age: Int) extends BasicProperties

def printProp(in: BasicProperties) =
  println(in.name+" is "+in.age+" years old")

E então você poderia chamar o método assim:

printProp(new Pet("Galfildo", 8))
printProp(new Person("Maria", 18))

Se você tivesse uma classe tipo:

class Antique(val name: String, val Age: int, val cost: int)

Você não poderia usar um objeto desse tipo como parametro para printProp, já que a classe não herda BasicProperties.

A solução está na capacidade que Scala tem de definir algo que poderia ser chamado de anonymous interfaces, no caso, o método printProp seria escrito assim:

def printProp(in: {def name: String; def age: Int}) =
  println(in.name+" is "+in.age+" years old")

Como se você estivesse definindo como parametro um tipo anonimo, que tem um método name do tipo String e um método age do tipo Int

E então poderia executar:

printProp(new Pet("Galfildo", 8))
printProp(new Person("Maria", 18))
printProp(new Antique("Monalisa", 450, 1000))

Como se ve, um código muito parecido com o escrito em Ruby e Python, mais ainda com uma caracteristica de documentação, já que o método é explicito sobre o que ele necessita.

Nenhum comentário:

Postar um comentário