Ingresar:

programacion java :: Blog :: Sobre los delegates de C#: una interfaz con clase

September 12, 2006

Marcelo muestra el uso de delegates en C# para realizar algunas estructuras de programación funcional en dicho lenguaje. Alvaro se pregunta por qué no hay delegates en Java. Yo he hecho algunas apreciaciones muy intuitivas con respecto a esos blogs y en este post intento describir lo que he comprendido del problema y mi propia posición.

En [1]: "Delegation is the ability to treat a method as a first-class object. A C# delegate is used where ... an interface with a single method."

Interesante. Entonces un delegate es una forma de proveer un método sin clase, mejor dicho sin más abstracción que su propia intención de funcionalidad (solo es una declaración ... eh .. uh una interfaz en el amplio sentido de la palabra). Desde el punto de vista conceptual orientado a objetos este ciudadado de primera clase no existiria. Si tuviera que modelarlo con UML .. usaría una interfaz, una clase abstracta o ... ¿un estereotipo <<delegate>>? ¿Modelamiento? Mmm bue, si, es un poco de "documentación" pero también se puede hacer antes de programar. Y ayuda ...

Un delegate no puede heredar de otro delegate. Esto seria irracional ya que solamente puede contener UN solo método [3]. Un delegate es un tipo de interfaz (en el sentido Java) terminal.

Pero también un delegate es un poco de clase. Algo en lo que me equivoqué completamente. Pensé que solamente era la abstracción, sin embargo hay también una semántica operacional detrás del concepto de delegate. ¡Un delegate se puede instanciar! Ejemplo de [3] abreviado:

  using System;
  delegate void D(int x);

  class Test
  {
    public void m1(int i)
    {
      Console.Writeln("Test.m1: " + i);
    }
  }

  class DemoDelegates
  {
    static void main()
    {
      D delegate1 = new D(Test.m1);
      delegate1(10);
    }
  }

En el método main de DemoDelegates, se crea la instancia a partir del delegate, pasando como parámetro el nombre de un delegate. Ups ... D funciona como constructor -- ¿no era un nombre de función? -- ... y toma como parámetro un método -- ¿no tenía como parámetro un entero? Y además la instacia habilita la ejecución del método pasado como parámetro, para que el método pueda ejecutarse en la próxima línea usando el nombre recién habilitado por la instanciación.

En realidad, en la declaración del delegate: D es el nombre de una clase abstracta, cuyo único método es abstracto y anónimo. Continúa la firma que especifica el tipo del parámetro (Int -> Void) que debe usarse para ser cotejado en tiempo de compilación cuando se creen instancias de esa clase, que en realidad son instancias de funciones que pueden ser invocadas con el nombre del objeto instanciado :-)

Ahora entiendo. No gracias, no lo compro, lo voy a dejar en el mostrador. Me quedo con la posibilidad de crear clases internas o clases anónimas (aunque a estas últimas no le veo sentido).

En [2] se explica por qué los diseñadores de Java no se dejaron convencer por el equipo de Microsoft de incluir en el lenguaje estos famosos delegates. Se argumenta sencillez del lenguaje, pero estamos hablando de Java 1.1. Luego de varias iteraciones del lenguaje no creo que sea un buen argumento para los pragmáticos. El lenguaje hoy en día está lejos de ser lo que era en otras épocas. Hay que mirar el diseño de las genéricas y sus consecuencias de implementación para darse cuenta de ello.

En [1] se muestra una implementación de delegates en Java para aquellos que no les gusta tener clases anónimas o clases anidadas, y además que emula la semántica operacional de los delegates. Muy interesante e instructivo para el programador que se aprecie a sí mismo. Una buena descripción de una semántica operacional posible para la sintaxis propuesta por Microsoft e implementada en su lenguaje C#. El uso de reflexión y la forma de forzar el chequeo de tipos son un buen ejemplo de  programación avanzada para los novatos.

Yo me he dejado convencer por [1]. Si esto se puede hacer en Java y se puede proveer una librería que lo haga, ¿por qué tuviera que ser una estructura del lenguaje? Se me ocurre una, pero dejamos este tema para la discusión ...

Referencias:

[1] Steven Lewis and Wilhelm Fitzpatrick.
    A Java programmer looks at C# delegates.
    ONJava.com, May 2003.
[2] The Java Language Team.
    About Microsoft's "Delegates".
[3] ECMA International.
    C# Language Specification. Fourth Edition.
    ECMA-334. June 2006.

Palabras clave: c#, java, programación avanzada

Enviado por Pablo Azero @ programacion java



Comentarios

  1. Recien leyendo tu nota me entero de lo feo que es instanciar delegates en C#. A mi también me pareció raro que el argumento al constructor no coincida con el tipo que declaras al delegate. Confuso para para no iniciados al C#. Gracias por el ejemplo.

    "Me quedo con la posibilidad de crear clases internas o clases anónimas (aunque a estas últimas no le veo sentido."

    Las clases anónimas son tan útiles como las funciones anónimas (lambdas), no todo tiene que tener un nombre. Tal vez es porque, como a mi, las clases anónimas te parecen repetitivas de escribir. Pero si fueran sencillas, más personas las usarían. En las conclusiones del artículo [1] los autores dicen:

    "In Swing programming, where large numbers of Runnables are needed to pass control to the swing thread, the ability to turn methods into Runnables is particularly useful. Delegates allow me to largely eliminate the need for anonymous inner classes, improving the readability of my code." 

    La alternativa pura que no use clases anónimas sería declarar una nueva clase para cada una de los eventos/runnables/etc? Con la imaginación que tengo empezaría a repetir los nombres de eventos una y otra vez, y luego hay que recordar como se llamaban , argh! 

    Mejor algo más corto como la librería que ellos proponen o incluir delegates al lenguaje.

    No estoy en desacuerdo en tener un lenguaje "puro", una menor cantidad de conceptos básicos hace que un lenguaje sea más fácil de aprender. Pero que pasa si eliges conceptos incompatibles con por ejemplo tener funciones de primera clase sin demasiada complicación sintáctica y semántica. Entonces estás obligado a extender tu lenguaje o hacer hacking sofisticado como el del artículo :).

    Gracias por mostrar el artículo. Si algún día vuelvo a programar en Java seguro que usaré una librería como esta. Tienes que hacer más trabajo que C# para tener los tipos correctos (y aún quedan riesgos), pero es casi tan fácil como en C#.

    user iconAlexey Rodriguez on Tuesday, 12 September 2006, 11:26 BOT # |

  2. Acabo de ver el "avatar" de este club. Quise verlo de cerca pero no puedo. De donde es el mapa? Puedo ver un zoom? :)

    user iconAlexey Rodriguez on Tuesday, 12 September 2006, 11:28 BOT # |

  3. Creo que las clases anónimas son útiles para salvar el momento, pero hay que refactorizarlas tarde o temprano en otras abstracciones más genéricas. El uso del patrón delegate puede ser una de las formas.  Supongo que con un poco de genéricas en ese patrón se pueden hacer cosas bonitas.

    El avatar? Es la isla de Java, qué mas puede ser? Lo suficientemente misterioso y exótico para encontrar algo interesante de la vida, no? :-) Bueno si alguien quiere cambiarlo estoy a la espera de alguna sugerencia.

    user iconPablo Azero on Tuesday, 12 September 2006, 20:32 BOT # |

  4. Ah! La isla de Java! :) Gracias por la aclaración.

    No te gustan las cosas anónimas, no? :) La refactorización acaba en una familia de combinadores/operaciones cuya aplicación puede ser única en cierto punto, en tal caso no veo porque poner un nombre si no es necesaria la reutilzación (aunque admito que puede llegar a serlo). Acabo de encontrar un mecanismo más corto: métodos anónimos en C#.

    Buena la idea de usar generics en el delegate Java, tal vez se puedan eliminar los casts.

    user iconAlexey Rodriguez on Wednesday, 13 September 2006, 04:30 BOT # |

  5. Tal vez no me he expresado con la precisión que la situación merece. Las cosas anónimas son útiles cuando están bien pensadas. El cálculo lambda está pensado originalmente con funciones sin nombres. El bautizo (nombrado? nombramiento?) de elementos está contemplado como una estructura del lenguaje y formalizado con reglas muy claras y precisas :-) En el caso de las clases y objetos?

    En principio una clase es una estructura reutilizable. No existe de por sí, solamente provee una estructura (tipo) para poder crear objetos. El hecho de que en algunas situaciones se necesite definir una clase muy simple para algún caso muy especial en el que es el único uso de la misma, y que para esos casos sea necesario proveer un mecanismo de programación más ágil es, hasta, soportable.

    He mirado el enlace que has enviado y ... bueno, da ganas de arrancarse los pelos. El título es: "Create Elegant Code with Anonymous Methods ...". He ido a la parte de "Anonymous methods". Encontramos este snippet:

    class SomeClass
    {
    delegate void SomeDelegate();
    public void InvokeMethod()
    {
    SomeDelegate del = delegate()
    {
    MessageBox.Show("Hello");
    };
    del();
    }
    }

    Es un delegate, no es un método, las cosas por su nombre. Como delegate la solución parece coherente. De mi análisis anterior ya sabíamos que el nombre de la clase-interfaz es SomeDelegate, pero el método es anónimo. La instanciación de la clase liga/enlaza (binds) un código y su nombre a este tipo. ¿Dónde está el new para crear la instancia? Hay una lógica para todo esto? Cada situación es una situación especial ... hay que crear cualquier artificio para escribir programas "elegantes" (sinónimo al parecer de, en realidad, "cortos").

    ¿Hay algo que me estoy perdiendo de estas lógicas de diseño? Avisenme asi leo la parte de "Partial Classes" que parece interesante. Este tipo de estructuras aparece ya en el lenguaje AG. Pero antes de hacer funcionar mi hígado quiero ver si hay una vacuna para ello :-)

    Ahora que lo pienso la declaración del delegate es básicamente un nombre de tipo para un método. Un tipo es una clase y por tanto se puede instanciar. ¿Cómo se instancia un tipo? Proveyendo código que se ajuste al tipo.

    user iconPablo Azero on Wednesday, 13 September 2006, 09:51 BOT # |

  6. Calma con ese hígado, no dije que eso fuera un método, es un delegate que encapsula un método anónimo, a diferencia del delegate en Java que encapsula un método con nombre.

    No deseo discutir acerca del desmérito de este diseño. Si quiero elegancia y lógica de diseño prefiero Haskell :). Mi impresión es que las decisiones de diseño que tomaron para C# y Java son incompatibles con ciertos idiomas de programación, como el uso de funciones anónimas/de primera clase. O por lo menos cuando los quieres incorporar, no se sienten naturales. Tanto el extraño diseño de C# como el hack con reflexión en Java son menos elegantes que funciones de primera clase en otros lenguajes. Y ninguno de los dos es particularmente más elegante que el otro en este aspecto, pero como en uno requiere menos esfuerzo y el compilador chequea los tipos, esa es mi preferencia por un mal menor.

    user iconAlexey Rodriguez on Thursday, 14 September 2006, 11:49 BOT # |

  7. Ahora si puedo decir que conozco el h'igado de un programador compulsivo ;).

    El debate se ha tornado interesante, aunque me hubiera gustado que mi pregunta inicial sea respondida mas desde el lado "acad'emico", es decir con algunos fundamentos de teor'ia de objetos o de diseño de lenguajes de programaci'on, porque veo que a ratos mezclamos muchas cosas en nuestros argumentos (hasta sobre la claridad del c'odigo se discute).

    A riesgo de ser llamado nuevamente "ac'olito de Bill Gates" por el Dr Pablo :p  encontr'e una entrevista con Anders Hejlsberg el arquitecto en jefe de C# hablando justamente sobre los delegates[1].

    Pero algo aun mas interesante es la idea siguiente:

    "Anders Hejlsberg has a brilliant track record as a language implementer (turning Turbo Pascal into the object oriented Delphi). Microsoft's position paper is naturally a reflection of Mr. Hejlsberg's views.  James Gosling  thought long and hard before deciding against adopting delegates in the Java language.  Mr. Gosling's apparent bias is toward the simplest expression of a programming language with the minimum number of programming abstractions, while Mr. Hejlsberg's bias leans toward program flexibility and execution efficiency."[2].

    No estoy de acuerdo con la idea de: "Si esto se puede hacer en Java y se puede proveer una librería que lo haga, ¿por qué tuviera que ser una estructura del lenguaje?", esto es muy discutible, alg'un momento yo podr'ia decir "entonces para que tener generics, si puedo hacer lo mismo solo con el lenguaje", ser'ia bueno definir "elegancia" y poner un dominio para la discuci'on, para que no mezclemos tomates con manzanas.

    Referencias:

    1. Delegates, Components, and Simplexity
        A Conversation with Anders Hejlsberg, Part III by Bill Venners with Bruce Eckel
        http://www.artima.com/intv/simplexity2.html

    2.  Evaluating Languages Mechanims.
         http://www.acisinc.com/evaluating.htm

     

     

    user iconAlvaro Sejas on Thursday, 14 September 2006, 16:10 BOT # |

  8. Parte de mi inquietud está resuelta. En [2] de la respuesta de Alvaro: "Mr. Gosling's apparent bias is toward the simplest expression of a programming language with the minimum number of programming abstractions, while Mr. Hejlsberg's bias leans toward program flexibility and execution efficiency."

    Coincido con la posición de James Gosling y eso es evidente.  Mis palabras eran: "Si esto se puede hacer en Java y se puede proveer una librería que lo haga, ¿por qué tuviera que ser una estructura del lenguaje?". Además, he dicho en el mensaje principal que Java ha dejado de ser un lenguaje simple, y casualmente el ejemplo que he mencionado son las genéricas.

    De la posición de Hejlsberg puedo suponer que la lógica de Microsoft es "program flexibility and execution efficiency". Es válido entonces asumir "cualquier cosa que satisfaga esta posición es buena para Microsoft". Por tanto entiendo el desorden. Para mi es punto final. Adicionalmente entiendo el desorden de Delphi. También, debo reconocer que, la palabra desorden parte de una percepción propia de orden. Pero bueno, cada quien debe construir su propio modelo mental ya que todavía no hay ecuaciones matemáticas para ello.

    Ambos argumentos son por demás subjetivos (ambos, el de Gosling y el de Hejlsberg), y por tanto el mio.  Sigue [2] de la respuesta de Alvaro: "Since we can't eliminate bias in our pursuit of the best programming language abstractions, we can at least endeavor to be reflective about our own preconceived notions and capture them in writing". El resto del mismo documento es interesante para entender algunos puntos de decisión que se deben enfrentar en el diseño/elección de lenguajes de programación. Gracias Alvaro por proveer ese enlace. En otro post puedo intentar ser más "académico", pero no esperes un curso de teoría formal de lenguajes orientados a objeto ;-)

    user iconPablo Azero on Friday, 15 September 2006, 17:31 BOT # |

Debes iniciar sesión para enviar un comentario.