Multimétodos

Las clausuras de multimétodos actúan como multimétodos. Recuérdese la definición que de multimétodos da la wikipedia:

Multiple dispatch or multimethods is the feature of some object-oriented programming languages in which a function or method can be dynamically dispatched based on the run time (dynamic) type of more than one of its arguments. This is an extension of single dispatch polymorphism where a method call is dynamically dispatched based on the actual derived type of the object. Multiple dispatch generalizes the dynamic dispatching to work with a combination of two or more objects.
generaciondecodigos@nereida:~/Lgroovy/closures$ cat -n multipledispatch.groovy                    
     1  #!/usr/bin/env groovy
     2  /*
     3  Multiple dispatch or multimethods is the feature of some object-oriented
     4  programming languages in which a function or method can be dynamically
     5  dispatched based on the run time (dynamic) type of more than one
     6  of its arguments. This is an extension of single dispatch polymorphism
     7  where a method call is dynamically dispatched based on the actual
     8  derived type of the object. Multiple dispatch generalizes the dynamic
     9  dispatching to work with a combination of two or more objects.
    10  */
    11  class MultiMethod {
    12    int f(String val) {
    13      val.length()
    14    }
    15
    16    int f(List list) {
    17      list.size()
    18    }
    19
    20    int f(int x, int y) {
    21      x+y
    22    }
    23  }
    24
    25  x = new MultiMethod()
    26
    27  println "Using method call:"
    28  println "On a string: ${x.f('string argument')}"
    29  println "On a list: ${x.f([1, 2, 3, 4, 'string'])}"
    30  println "On numbers: ${x.f(3, 4)}"
    31
    32  c = x.&f
    33
    34  println "Using closure:"
    35  println "On a string: ${c('string argument')}"
    36  println "On a list: ${c([1, 2, 3, 4, 'string'])}"
    37  println "On numbers: ${c(3, 4)}"
generaciondecodigos@nereida:~/Lgroovy/closures$
Sigue el resultado de una ejecución:

generaciondecodigos@nereida:~/Lgroovy/closures$ ./multipledispatch.groovy
Using method call:
On a string: 15
On a list: 5
On numbers: 7
Using closure:
On a string: 15
On a list: 5
On numbers: 7

Cuando se trabaja con multimétodos pueden surgir dudas sobre que método concreto será llamado. ¿Que métodos serán llamados en este ejemplo?

generaciondecodigos@nereida:~/Lgroovy/closures$ cat -n mm.groovy                                  
     1  #!/usr/bin/env groovy                                                                     
     2  class Person {                                                                            
     3      String name                                                                           
     4                                                                                            
     5      Person(String name) {                                                                 
     6          this.name = name                                                                  
     7      }                                                                                     
     8                                                                                            
     9      Person() {                                                                            
    10          this.name = ""                                                                    
    11      }                                                                                     
    12                                                                                            
    13      boolean equals(Object o) {                                                            
    14          println("equals(Object o)")                                                       
    15          // delegate on Groovy equality                                                    
    16          name == o                                                                         
    17      }                                                                                     
    18                                                                                            
    19      boolean equals(Person emp) {                                                          
    20          println("equals(Person emp)")
    21          name == emp.name
    22      }
    23  }
    24
    25       void test1() {
    26          println "==================== test1"
    27          Object e1 = new Person("Juana")
    28          Object e2 = new Person("Juana")
    29          println(e1.equals(e2))       // Person
    30          println(e1.equals(e1))       // Person
    31          println(e1.equals("Juana"))  // Object
    32      }
    33
    34       void test2() {
    35          println "==================== test2"
    36          Person e1 = new Person("Juana") 
    37          Person e2 = new Person("Juana")
    38          println(e1.equals(e2))        // Person
    39          println(e1.equals(e1))        // Person
    40          println(e1.equals("Juana"))   // Object
    41      }
    42
    43
    44       void test3() {
    45          println "==================== test3"
    46          e1 = new Person("Juana")
    47          e2 = new Person("Juana")
    48          println(e1.equals(e2))        // Person
    49          println(e1.equals(e1))        // Person
    50          println(e1.equals("Juana"))   // Object
    51      }
    52
    53
    54  test1()
    55  test2()
    56  test3()
En la primera prueba los objetos son explícitamente declarados de la clase Object. En la segunda de la clase Person. En la tercera no hay declaración explícita.

El resultado de las ejecuciones es el mismo en los tres casos:

generaciondecodigos@nereida:~/Lgroovy/closures$ ./mm.groovy
==================== test1
equals(Person emp)
true
equals(Person emp)
true
equals(Object o)
true
==================== test2
equals(Person emp)
true
equals(Person emp)
true
equals(Object o)
true
==================== test3
equals(Person emp)
true
equals(Person emp)
true
equals(Object o)
true

Casiano Rodríguez León
2010-04-30