Como os tipos existenciais diferem das interfaces?

11

Dado o tipo existencial

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

e essa interface Java genérica:

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

Quais são as diferenças fundamentais entre o tipo existencial e a interface Java?

Obviamente, existem diferenças sintáticas e a orientação a objetos do Java (que também inclui detalhes como thisparâmetros ocultos etc.). Não estou muito interessado nelas, mas em diferenças conceituais e semânticas - embora se alguém quiser esclarecer alguns pontos mais delicados (como a diferença notacional entre Tvs. T<X>), isso também seria apreciado.

stakx
fonte

Respostas:

4

Hmm ... Essa definição se parece muito com uma amostra de haskell que eu já vi há muito tempo.

{-# 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]

Quando o construtor Xé aplicado, ele se torna realmente. Observe que, quando você retira value, não conhece o tipo e possui um conjunto de operações vazio sobre ele. Mas já que viewValueé meio coerente com valueele, pode ser aplicado a ele.

Eu acho que a principal diferença de Java que interfacevocê propôs é o fato de que você precisa conhecer o tipo intermediário para passar o resultado de op₁para op₂. Ou seja, o sistema adequado para o tipo existencial deve selecionar o tipo certo que é garantido que existe por condição. Ou seja, você deve ser capaz de escrever a função com o tipo: ∀X. X→(X→boolean)→T. Na amostra anterior, essa função é Xusada no construtor X 3 show( showé uma função que aceita argumentos de qualquer tipo que implementa Showe retorna String)

Atualizado: Acabei de reler sua pergunta e acho que tenho uma construção adequada 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₂()) ...

Você está certo sobre mencionar this- na verdade é sua opção.

Então, acho que entendi agora que linguagens clássicas de POO (Java, C #, C ++ etc.) sempre implementam tipo existencial com valor único thise uma função chamada "métodos", chamada implicitamente com esse valor :)

PS Desculpe, não estou muito familiarizado com Java, mas espero que você tenha entendido.

ony
fonte
Acrescentarei a isso que você deve consultar o tipo SAM (Single Abstract Method) que está sendo introduzido no Java 8 para suporte à programação funcional.
Martijn Verburg
2

A única diferença é que a interface Java realmente significa algo para o compilador Java.

O tipo existencial é a definição formal de um tipo, não específico para qualquer idioma. Os cientistas da computação usam esse tipo de definição para provar coisas sobre o tipo e sobre as linguagens que o implementam. A interface Java é uma das implementações de Java do tipo definido formalmente.

Matthew Flynn
fonte
Não. cf william cozinhar papel.
226
2

Os 2 tipos apresentados são muito diferentes um do outro. A definição da interface que você escreveu é do tipo universal (os genéricos Java geralmente se enquadram nessa categoria).

Um tipo existencial oculta um tipo em sua implementação do consumidor. Intuitivamente, para que X seja existencial em T, a identidade de X não pode ser conhecida de nenhum consumidor; tudo o que deve ser conhecido é o conjunto de operações fornecidas na definição. Existe um tipo T para algum tipo X.

Por outro lado, um tipo universal define operações aplicáveis ​​a todos os tipos, dentre os quais o consumidor é livre para escolher. O tipo de interface T é exatamente isso. X é instanciado pelo consumidor, que saberá exatamente qual é o tipo X. Existe um tipo T para cada tipo X no universo.

Os existenciais não estão realmente presentes em Java como uma construção de linguagem, exceto no caso limitado de caracteres curinga ( List<?>). Mas sim, eles podem ser emulados com interfaces. O problema passa a ser mais de design.

Como ony apontou, em um cenário orientado a objeto, os existenciais se tornam difíceis de implementar porque a maneira como você normalmente codifica as informações de tipo de X (o que você pode fazer com isso) é ter funções de membro em um tipo de interface que X implementa. Em resumo, as interfaces podem comprar alguns recursos de abstração de tipo, mas exigem a eliminação do existencial até certo ponto.

Rafael
fonte