net for español development c# java python dynamic-languages

c# - for - ¿Por qué no requerimos interfaces en lenguajes dinámicos?



python vs c++ (9)

¿Es solo por la escritura dinámica que no necesitamos un concepto de interfaces (como en Java y C #) en python?


En C # y Java, las interfaces son solo clases abstractas con todos los métodos abstractos. Existen para permitir una pseudo herencia múltiple sin ser realmente compatibles con la herencia múltiple completa y la ambigüedad crea la herencia múltiple.

Python admite la herencia múltiple y tiene su propia forma de determinar qué método de los padres debe llamarse cuando existe un método en varios padres.


Java 1 introdujo la interface como palabra clave y artefacto (y C # la tomó de allí) para describir el contrato que debe cumplir un objeto.

Pero, la interfaz siempre ha sido una parte clave del Paradigma Orientado a Objetos y básicamente representa los métodos que debe responder un objeto. Java solo aplica este mecanismo para proporcionar una comprobación de tipos estática.

Por lo tanto, los lenguajes de programación dinámicos (OO) utilizan interfaces, incluso si no los verifican de forma estática. Al igual que otros tipos de datos, por ejemplo en Ruby:

@i = 1;

No tiene que declarar i del tipo FixNum , simplemente lo utiliza. Lo mismo ocurre con las interfaces, simplemente fluyen. La compensación es que no se puede realizar una comprobación estática y los fallos solo se muestran en el tiempo de ejecución.

Por otro lado, el tipo estructural (o el tipo de pato estático, como yo lo llamo: P), utilizado por idiomas como Go o Scala, ofrece lo mejor de ambos mundos.

1. Ver el comentario de Daniel Earwicker sobre la palabra clave de la interface CORBA


Las construcciones de interfaz se utilizan en lenguajes de tipo estático para enseñar al sistema de tipos qué objetos son sustituibles entre sí en un contexto particular de invocación de métodos. Si dos objetos implementan el mismo método pero no están relacionados a través de la herencia de una clase base común o la implementación de una interfaz común, el sistema de tipos generará un error en el momento de la compilación si sustituye uno por el otro.

Los lenguajes dinámicos usan "escritura de pato", lo que significa que el método simplemente se busca en tiempo de ejecución y, si existe con la firma correcta, se usa; De lo contrario se produce un error de tiempo de ejecución. Si dos objetos, "quack como un pato" implementando el mismo método, son sustituibles. Por lo tanto, no hay una necesidad explícita de que el lenguaje los relacione a través de la clase base o la interfaz.

Dicho esto, las interfaces como concepto siguen siendo muy importantes en el mundo dinámico, pero a menudo solo se definen en la documentación y no se aplican en el lenguaje. De vez en cuando, veo que los programadores en realidad forman una clase base que dibuja la interfaz para este propósito también; esto ayuda a formalizar la documentación, y es de uso particular si parte de la interfaz se puede implementar en términos del resto de la interfaz.


Las interfaces se utilizan en lenguajes de tipo estático para describir que dos objetos independientes de otro modo "implementan el mismo comportamiento". En los idiomas tipeados dinámicamente, uno asume implícitamente que cuando dos objetos tienen un método con el mismo nombre / params, hace lo mismo, por lo que las interfaces no sirven para nada.


Los lenguajes dinámicos están tipificados en pato

Si camina como un pato y grazna como un pato, debe ser un pato.

http://en.wikipedia.org/wiki/Duck_typing

En otras palabras, si selecciona un objeto para apoyar el método Delete (), entonces puede usar el

obj.Delete()

método, pero si el objeto no es compatible con Eliminar (), obtendrá un error de tiempo de ejecución. Los idiomas escritos de forma estática no permitirían eso y arrojarían un error de tiempo de compilación. Básicamente, usted intercambia el tipo de seguridad contra un tiempo de desarrollo y flexibilidad más rápidos.

Sin interfaces puedes hacer algo así en lenguajes estáticos:

void Save(MyBaseClass item) { if (item.HasChanges) item.Save() }

pero eso requeriría que cada objeto que pase a este método heredara de MyBaseClass. Ya que Java o C # no admiten la herencia de muli, no es muy flexible porque si su clase ya hereda otra clase, tampoco puede heredar de MyBaseClass. Por lo tanto, la mejor opción sería crear una interfaz ISavable y aceptar eso como un parámetro de entrada para garantizar que ese elemento se pueda guardar. Entonces tienes lo mejor de ambos: seguridad y flexibilidad.

public interface ISavable { bool HasChanges {get;set;} void Save(); } void Save(ISavable item) { if (item.HasChanges) item.Save() }

La última puerta trasera es usar el objeto como parámetro si no puede esperar que todos los elementos que usarán su método de guardar implementen la interfaz.

void Save(object item) { if (item.HasChanges) item.Save() }

Pero, una vez más, no tiene verificación de tiempo de compilación y probablemente obtenga un error de tiempo de ejecución si alguien usa su método con una clase incompatible.


No los requerimos , pero los apoyamos . Echa un vistazo a las interfaces Zope (que pueden ser y se utilizan fuera de Zope).



Una cosa clave acerca de al menos algunos lenguajes dinámicos que hacen que las interfaces explícitas sean algo más torpes es que los lenguajes dinámicos a menudo pueden responder a los mensajes (err, “llamadas a métodos”) que no conocen de antemano, incluso haciendo cosas como crear métodos. sobre la marcha. La única forma real de saber si un objeto responderá a un mensaje correctamente es enviándolo. Eso está bien, porque los lenguajes dinámicos consideran que es mejor poder admitir ese tipo de cosas en lugar de la comprobación de tipos estática; se considera que un objeto es utilizable en un protocolo particular porque se sabe que puede participar en ese protocolo (por ejemplo, en virtud de que otro mensaje lo da).


Vale la pena señalar que, al contrario de lo que dirá mucha gente como primera respuesta, las interfaces se pueden usar para hacer más que documentar "qué métodos admite una clase". Grzenio toca esto con su redacción sobre "implementar el mismo comportamiento". Como ejemplo específico de esto, mire la interfaz de Java Serializable. No implementa ningún método; más bien se usa como un "marcador" para indicar que la clase puede ser serializada de manera segura.

Cuando se considera de esta manera, podría ser razonable tener un lenguaje dinámico que use interfaces. Dicho esto, algo parecido a las anotaciones podría ser un enfoque más razonable.