¿Qué es "duck typing"?

Tal vez habrás notado que en Ruby no declaramos los tipos de las variables o métodos. To do es sólo un tipo de objeto. Los objetos Ruby (a diferencia de os objetos en otros lenguajes orientados a objetos) pueden ser modificados individualmente. Siempre puedes agregar métodos objeto por objeto. En Ruby, el comportamiento o capacidades de un objeto puede desviarse de aquellos definidos en su clase.

En Ruby, confiamos menos en el tipo (o clase) de un objeto y más en sus capacidades. Entonces, Duck Typing significa que el tipo de un objeto está definido por lo que puede hacer, no por lo que es. Duck Typing se refiere a la tendencia de Ruby de preocuparse menos por la clase de un objeto y más por los métodos que pueden ser llamados por el y las operaciones que se pueden realizar con en el. En Ruby utilizaríamos el método respond_to? o simplemente pasamos un objeto a un método y sabemos que se generará una excepción si se utiliza inapropiadamente.

Si un objeto camina como un pato (walks like a duck) y habla como pato (talks like a duck), entonces el intérprete es feliz de tratarlo como si fuera un pato.

Considera el siguiente ejemplo:

1 # Verificar si el objeto defin el metodo to_str
2 puts 'Una cadena'.respond_to?(:to_str)
3 puts Exception.new.respond_to?(:to_str)
4 puts 4.respond_to?(:to_str)

El ejemplo anterior es el ejemplo más simple de la filosofía duc typing de Ruby: si un objeto grazna como pato (o actúa como una cadena), trátalo como a un pato (o una cadena). Cuando sea posible, debes tratar a un objeto de acuerdo a los métodos que define en vez de a la clase de la que hereda o los módulos que incluye.

Considera el siguiente ejemplo: p036pato.rb

 1 class Pato
 2   def grazna
 3     'Quack!'
 4   end
 5 
 6   def nada
 7     'Rema, rema, rema...'
 8   end
 9 end
10 
11 class Ganso
12   def grazna
13     'Hock!'
14   end
15 
16   def nada
17     'Splash splash splash...'
18   end
19 end
20 
21 class GrabacionDePato
22   def grazna
23     play
24   end
25 
26   def play
27     'Quack!'
28   end
29 end
30 
31 def hazlo_graznar(pato)
32   pato.grazna
33 end
34 puts hazlo_graznar(Pato.new)
35 puts hazlo_graznar(GrabacionDePato.new)
36 
37 def hazlo_nadar(pato)
38   pato.nada
39 end
40 puts hazlo_nadar(Pato.new)
41 puts hazlo_nadar(Ganso.new)

Observa el siguiente código:

1 def hazlo_graznar(pato)
2   pato.grazna
3 end
4 puts hazlo_graznar(Pato.new)
5 puts hazlo_graznar(GrabacionDePato.new)

Un método que le dice a un pato que grazne funciona cuando le pasas un objeto GrabacionDePato gracias al duck typing. De manera similar, en el siguiente código:

1 def hazlo_nadar(pato)
2   pato.nada
3 end
4 puts hazlo_nadar(Pato.new)
5 puts hazlo_nadar(Ganso.new)

Un método que le dice a un pato que nade, funciona para un ganso.