¿Cómo difieren los tipos existenciales de las interfaces?

11

Dado el tipo existencial

T = X.{op₁:X, op₂:Xboolean}

y esta interfaz genérica de Java:

interface T<X> {
    X op₁();
    boolean op₂(X something);
}

¿Cuáles son las diferencias fundamentales entre el tipo existencial y la interfaz Java?

Obviamente hay diferencias sintácticas y la orientación a objetos de Java (que también incluye detalles como thisparámetros ocultos , etc.). No estoy tan interesado en esto como en las diferencias conceptuales y semánticas, aunque si alguien quisiera arrojar luz sobre algunos puntos más finos (como la diferencia de notación entre Tvs. T<X>), eso también sería apreciado.

stakx
fuente

Respuestas:

4

Hmm ... Esa definición se parece mucho a una muestra de haskell que he visto hace mucho tiempo.

{-# LANGUAGE ExistentialQuantification #-}
data X = forall a . X { value :: a, viewValue :: a -> String }
instance Show X where show (X { value = x, viewValue = f}) = f x
sample :: [X]
sample = [X 3 show, X "abc" show, X 3.14 show]

Cuando Xse aplica el constructor ∀ en realidad se convierte en ∃. Tenga en cuenta que cuando saca valueno conoce el tipo y tiene un conjunto de operaciones vacío sobre él. Pero dado que viewValuees un poco coherente con valueél, se le puede aplicar.

Supongo que la principal diferencia de Java interfaceque propuso es el hecho de que debe conocer el tipo intermedio para pasar el resultado de op₁a op₂. Es decir, el sistema adecuado para el tipo existencial debe seleccionar el tipo correcto que se garantiza que existe por condición. Es decir, que debe ser capaz de escribir con función de tipo: ∀X. X→(X→boolean)→T. En la muestra anterior, dicha función es un Xconstructor utilizado X 3 show( showes una función que toma argumentos de cualquier tipo que implementa Showy devuelve String)

Actualizado: acabo de volver a leer su pregunta y creo que tengo una construcción adecuada para Java:

interface T {
    boolean op₂();
}
...
T x = new T() {
    private final int op = ...;
    public boolean op₂() { return ((op % 2) == 0); }
};
T y = new T() {
    private final char op = ...;
    public boolean op₂() { return ('0' <= op && op <= '9'); }
};
if (x.op₂() && y.op₂()) ...

Tienes razón al mencionar this: en realidad es tu opción.

Así que supongo que entendí ahora que los lenguajes clásicos de OOP (Java, C #, C ++, etc.) siempre implementan el tipo existencial con un solo valor thisy unas funciones sobre él llamadas "métodos" que implícitamente llaman con ese valor :)

PD: Lo siento, no estoy muy familiarizado con Java, pero espero que tengas la idea.

ony
fuente
Agregaré a esto que querrá ver el tipo de método abstracto único (SAM) que se está introduciendo en Java 8 para soporte de programación funcional.
Martijn Verburg el
2

La única diferencia es que la interfaz de Java realmente significa algo para el compilador de Java.

El tipo existencial es la definición formal de un tipo, no específica de cualquier idioma. Los informáticos usan este tipo de definición para probar cosas sobre el tipo y sobre los idiomas que lo implementan. La interfaz de Java es una de las implementaciones de Java del tipo formalmente definido.

Matthew Flynn
fuente
no cf william cocinar papel.
nicolas
2

Los 2 tipos presentados son muy diferentes entre sí. La definición de interfaz que ha escrito es de tipo universal (los genéricos de Java en general pertenecen a esta categoría).

Un tipo existencial oculta un tipo dentro de su implementación del consumidor. Intuitivamente, para que X sea existencial en T, la identidad de X no puede ser conocida por ningún consumidor; todo lo que se debe saber es el conjunto de operaciones proporcionadas en la definición. Existe un tipo T para algún tipo X.

Por el contrario, un tipo universal define operaciones aplicables a todos los tipos, de los cuales el consumidor es libre de elegir. El tipo de interfaz T es exactamente eso. X es instanciado por el consumidor, quien sabrá exactamente qué tipo X es. Existe un tipo T para cada tipo X en el universo.

Los existenciales no están realmente presentes en Java como una construcción de lenguaje, excepto en el caso limitado de comodines ( List<?>). Pero sí, se pueden emular con interfaces. El problema se vuelve más de diseño.

Como se señaló anteriormente, en un entorno orientado a objetos, los existenciales se vuelven difíciles de implementar porque la forma en que generalmente codifica la información de tipo de X (lo que puede hacer con él) es tener funciones miembro en un tipo de interfaz que X implementa. En resumen, las interfaces pueden comprar algunas capacidades de abstracción de tipo, pero requieren la eliminación de lo existencial hasta cierto punto.

Rafael
fuente