Sottotipo implicito vs esplicito


18

Questa pagina afferma che

molte lingue non usano il sottotipo implicito (equivalenza strutturale), preferendo il sottotipo esplicito / dichiarato (equivalenza di dichiarazione)

Ho principalmente usato linguaggi di programmazione che usano il sottotipo esplicito . Quali sono i vantaggi del sottotipo implicito, come descritto nelle note sopra.


1
Dalle FAQ, nell'ambito di questo scambio: "Il lavoro in questo campo si distingue spesso per la sua enfasi sulla tecnica matematica e il rigore". Sto votando perché non vedo alcun margine di rigore nelle risposte a questa domanda.
David Eppstein,

6
Purtroppo, nel rispondere a questa domanda c'è molto più margine di rigore di quanto inizialmente si possa sperare. Molte persone eminenti hanno bruciato molti degli anni '90 alle prese con domande apparentemente banali sul sottotipo. Purtroppo è un'area con un rapporto sforzo-ricompensa molto scarso.
Neel Krishnaswami,

6
sì, c'è un sacco di spazio per la matematica e il rigore nel rispondere a questa domanda, o almeno a spiegare matematicamente ciò che subtyping implicita è . Non sono sicuro del rapporto sforzo-ricompensa.
Noam Zeilberger,

1
Probabilmente avrei dovuto solo dire che era "molto difficile", poiché dopo aver riflettuto mi rendo conto di essere molto interessato alle risposte.
Neel Krishnaswami,

1
Ok, sono convinto. Rimuoverei il mio downvote ma il sistema non me lo permette.
David Eppstein,

Risposte:


19

La risposta breve è "verificare proprietà aggiuntive del codice esistente". Segue una risposta più lunga.

Non sono sicuro che "implicito" vs "esplicito" sia una buona terminologia. Questa distinzione è talvolta chiamata sottotipizzazione "strutturale" vs "nominale". Vi è poi anche una seconda distinzione nelle possibili interpretazioni del sottotipo strutturale (descritte a breve). Nota che tutte e tre le interpretazioni del sottotipo sono davvero ortogonali, e quindi non ha davvero senso confrontarle tra loro, piuttosto che comprendere gli usi di ciascuno.

La principale distinzione operativa nell'interpretazione di una relazione di sottotipo strutturale A <: B è se è assistito da una vera coercizione con contenuto computazionale (runtime / compiletime) o se può essere assistito dalla coercizione dell'identità. Se la prima, l'importante proprietà teorica che deve avere è la "coerenza", cioè se ci sono diversi modi per dimostrare che A è un sottotipo di sottostruttura di B, ciascuna delle coercizioni che la accompagnano deve avere lo stesso contenuto computazionale.

Il collegamento che hai dato sembra avere in mente la seconda interpretazione del sottotipo strutturale, in cui A <: B può essere testimoniato dalla coercizione dell'identità. Questa è talvolta chiamata "interpretazione di sottoinsieme" del sottotipo, considerando l'ingenua visione che un tipo rappresenta un insieme di valori, e quindi A <: B nel caso in cui ogni valore di tipo A sia anche un valore di tipo B. È anche a volte chiamato "refinement typing", e un buon documento da leggere per la motivazione originale sono i tipi di affinamento di Freeman & Pfenning per ML . Per una più recente incarnazione in F #, puoi leggere Bengston et al, Tipi di perfezionamento per implementazioni sicure. L'idea di base è quella di prendere un linguaggio di programmazione esistente che potrebbe (o potrebbe non avere) già dei tipi ma in quali tipi non garantisce così tanto (ad esempio, solo la sicurezza della memoria) e prendere in considerazione un secondo livello di tipi selezionando sottoinsiemi di programmi con proprietà aggiuntive e più precise.

(Ora, direi che la teoria matematica alla base di questa interpretazione del sottotipo non è ancora ben compresa come dovrebbe essere, e forse è perché i suoi usi non sono così ampiamente apprezzati come dovrebbero. Un problema è che il "set di valori "l'interpretazione dei tipi è troppo ingenua, e quindi a volte viene abbandonata anziché perfezionata. Per un altro argomento secondo cui questa interpretazione del sottotipo merita più attenzione matematica, leggi l'introduzione ai Sottospazi di Paul Taylor in Abstract Stone Duality .)


Ciao Noam, bella risposta! Aggiungerò che il sottotipo nominale alla OO è fondamentalmente un modo per definire una classe di coercizioni di non identità che sono comunque realizzate da no-ops. Cioè, il sottotipo di larghezza degli oggetti indotti dall'ereditarietà comporta formalmente una coercizione di non identità (ad es. coercizione significa che butti via la ), ma disponendo i record in sequenza in memoria è possibile utilizzare lo stesso codice binario per proiettare i componenti e per entrambi i tipi. C A BA×B×C<:A×BCAB
Neel Krishnaswami,

1
È compito dell'ottimizzatore capire il layout di memoria ottimale, quindi le coercizioni che sono identità dovrebbero essere il risultato dell'ottimizzazione.
Andrej Bauer,

2
quindi solo per chiarire il commento di Andrej rispetto alla mia risposta, in una raffinatezza tipizzante interpretativa, le relazioni di sottotitolo sono sempre testimoniate dalla coercizione dell'identità per definizione , perché i tipi di raffinamento non portano alcun contenuto computazionale extra. In altre parole, se A e B sono due perfezionamenti ("sottoinsiemi" / "proprietà") di un tipo di valori X, A <: B afferma che per ogni valore x in X, se x: A, allora anche x: B. Tale affermazione può essere verificata o falsificata, ma non ha alcun effetto in fase di esecuzione, poiché le prove che x: A e x: B non esistono in fase di esecuzione.
Noam Zeilberger,

1
@Noam: sono d'accordo, ma solo quando stiamo parlando della metatheory di una singola lingua, e non se stiamo parlando di compilation. Le coercizioni di identità possono essere realizzate con procedure che fanno molto lavoro, e le coercizioni di non identità possono essere realizzate con procedure che non fanno nulla. Concretamente, supponiamo di avere un tipo e un perfezionamento . Quindi potremmo implementare elementi del perfezionamento con una sola parola senza riquadri, anche se l'intero tipo richiede l'allocazione di memoria per rappresentare. Le coercizioni di identità qui devono essere realizzate mediante calcolo reale. { x : NN{x:N|x<232}
Neel Krishnaswami,

3
@Neel: lo dividerei in due passaggi, 1. applicare il calcolo - libera coercizione dell'identità da al suo raffinamento , quindi 2., applica la coercizione parzialmente definita da al tipo (completamente separato) di singole parole non in scatola, che è totalmente definito al raffinamento . Forse sta dividendo i peli ... ma in ogni caso questo dimostra che ho detto "che la teoria matematica alla base di questa interpretazione del sottotipo non è ancora ben compresa come dovrebbe essere" :){ x : N | x < 2 32 } N { x : N | x < 2 32 }N{x:N|x<232}N{x:N|x<232}
Noam Zeilberger,

4

Questa risposta è una sorta di supplemento minimo all'ottima risposta di Noam. Un punto di interesse dei dati è il destino dei concetti di C ++, fondati sul tentativo di unificare le nozioni nominali e strutturali di tipo.

C'è un eccellente resoconto qui, con collegamenti a gran parte della discussione pertinente: http://bartoszmilewski.wordpress.com/2010/06/24/c-concepts-a-postmortem/

Tuttavia, il precedente writeup non discute in modo approfondito il problema nominale rispetto a quello strutturale. C'è un altro writeup qui, che fa: http://nerdland.net/2009/07/alas-concepts-we-hardly-knew-ye/

Il documento chiave su entrambi punta è "Semplificare l'uso dei concetti" di Bjarne Stroustrup: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2906.pdf , che entra nella pratica problemi riscontrati in modo approfondito.

Nel complesso, la discussione è più pragmatica che rigorosa. Tuttavia, fornisce una buona visione del tipo di compromessi coinvolti in questi problemi, in particolare nel contesto di una grande lingua esistente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.