Perché 'vuoto' non è consentito come tipo generico in C #


53

Quali sono state le decisioni di progettazione che hanno sostenuto il fatto di voidnon essere costruibili e di non essere ammessi come tipo generico? Dopotutto è solo un vuoto speciale structe avrebbe evitato il PITA totale di avere distinti Funce Actiondelegati.

(C ++ consente voidrendimenti espliciti e consente voidcome parametro modello)


13
@Oded Considerando che Eric Lippert ha un account e partecipa ai programmatori , penso che l'abbia appena fatto.
Thomas Owens

2
@BenVoigt Non richiede necessariamente la conoscenza di un singolo individuo, anche se qui c'è una sola persona che può (facilmente, presumo) dare la sola risposta giusta. Chiunque abbia familiarità con le specifiche può probabilmente rispondere alla domanda, soprattutto se ha una conoscenza della progettazione del linguaggio di programmazione. È anche un'interessante domanda di progettazione / implementazione del linguaggio, che è in argomento qui.
Thomas Owens

6
@BenVoigt: Perché sei così desideroso di avere una domanda perfettamente valida e interessante chiusa senza una buona ragione, se non altro per soddisfare la tua pedanteria? Ho fatto una ricerca e non sono riuscito a trovare la risposta; forse qualcuno qui ha letto un post sul blog a riguardo, forse le persone che hanno preso la decisione vogliono rispondere alla domanda, forse qualcuno ha chattato con le persone che hanno preso la decisione al riguardo e si sono poste la domanda da soli e possono trasmettere la risposta. Ho smesso di pubblicare su questo sito e SO praticamente perché le persone sembrano molto più interessate a chiudere una domanda che a rispondere alle domande.

4
Potrei sottolineare le domande e le risposte "importanti" qui e specialmente su SO sono generalmente della forma "che cosa significa questa sintassi?" Quelle domande non si chiudono quasi mai perché tutti possono accumulare e rielaborare le definizioni per i cercatori di costanti e gli oggetti costanti. Le domande più interessanti che si trovano fuori dai sentieri battuti vengono perseguitate dal sito per qualche motivo pedante: sul serio sono solo pochi kilobyte in un data warehouse da qualche parte. Possiamo semplicemente rilassarci e abbracciare l'apprendimento piuttosto che imporre regole interpretate arbitrariamente che hanno uno scopo molto limitato?

2
@ThomasOwens: sono in un certo senso più attivo su questo sito che su SO. Su questo sito invio una risposta a circa una domanda ogni 300. Su SO inserisco una risposta a circa una domanda ogni 1500. La differenza nell'attività di puro numero di risposte è attribuibile al numero molto più elevato di opportunità per rispondere a domande C # su SO.
Eric Lippert,

Risposte:


69

Il problema fondamentale con "void" è che non significa la stessa cosa di qualsiasi altro tipo restituito. "vuoto" significa "se questo metodo ritorna, allora non restituisce alcun valore". Non nullo; null è un valore. Non restituisce alcun valore.

Questo incasina davvero il sistema dei tipi. Un sistema di tipi è essenzialmente un sistema per fare deduzioni logiche su quali operazioni sono valide su valori particolari; un metodo di ritorno vuoto non restituisce un valore, quindi la domanda "quali operazioni sono valide su questa cosa?" non ha alcun senso. Non c'è "cosa" perché ci sia un'operazione su, valida o non valida.

Inoltre, questo incasina il runtime qualcosa di feroce. Il runtime .NET è un'implementazione del Virtual Execution System, specificato come stack machine. Cioè, una macchina virtuale in cui le operazioni sono tutte caratterizzate in termini di effetto su uno stack di valutazione. (Naturalmente in pratica la macchina verrà implementata su una macchina con stack e registri, ma il sistema di esecuzione virtuale assume solo una pila.) L'effetto di una chiamata a un metodo vuoto è fondamentalmentediverso dall'effetto di una chiamata a un metodo non vuoto; un metodo non vuoto mette sempre qualcosa in pila, che potrebbe essere necessario schioccare. Un metodo vuoto non mette mai qualcosa in pila. E quindi il compilatore non può trattare i metodi void e non void allo stesso modo nel caso in cui il valore restituito dal metodo venga ignorato; se il metodo è nullo, non vi è alcun valore restituito, quindi non deve esserci alcun pop.

Per tutti questi motivi, "void" non è un tipo che può essere istanziato; non ha valori , questo è tutto. Non è convertibile in oggetto, e un metodo di ritorno del vuoto non potrà mai, mai essere trattato polimorficamente con un metodo di ritorno del vuoto, perché corrompe lo stack!

Pertanto, il vuoto non può essere usato come argomento di tipo, il che è un peccato, come si nota. Sarebbe molto conveniente.

Con il senno di poi, sarebbe stato meglio per tutti gli interessati se invece di nulla, un metodo di ritorno del vuoto restituisse automaticamente "Unità", un magico tipo di riferimento singleton. Sapresti quindi che ogni chiamata di metodo mette qualcosa nello stack , sapresti che ogni chiamata di metodo restituisce qualcosa che potrebbe essere assegnato a una variabile di tipo oggetto e, naturalmente, Unità potrebbe essere usata come argomento di tipo , quindi ci sarebbe non è necessario disporre di tipi di delegato Action e Func separati. Purtroppo, non è questo il mondo in cui ci troviamo.

Per qualche altro pensiero in questa vena vedi:


C ++ lo supporta senza dover usare un tipo singleton magico. Ma suppongo che abbia a che fare con C ++ usando uno stile "generics" completamente diverso da C #.
Winston Ewert,

4
@WinstonEwert - Sono abbastanza sicuro che C ++ non supporti affatto i generici, ma piuttosto ha modelli, che sono fondamentalmente diversi. A quanto ho capito, con i template il compilatore sta facendo una ricerca globale e lo sostituisce con i parametri del tipo, ma con i generici, il sistema dei tipi sta creando un tipo corretto. Penso anche che sia per questo che gli errori del modello C ++ fossero così ottusi. Sono sicuro che Eric mi correggerà se ho detto qualcosa che non va
Adam Rackis

1
Penso che tutte le strutture siano gestite al momento della compilazione per ottenere il corretto posizionamento in pila e in altri punti in cui sono allineati. Quindi Voiddovrebbe essere ok per essere passato come infinita quantità di argomenti all'interno di 0 byte di stack. Quando una struttura ha bisogno di essere convertita in objecto chiamare il metodo (per ottenerla this), la scatola deve essere posizionata sull'heap con il Typeriferimento inserito prima dell'area dei campi della memoria (per molte implementazioni CLR) e quindi potrebbe essere gestita correttamente. Per quanto mi riguarda, digitare è solo un grupping di oggetti che può essere distinto da alcune caratteristiche (campi). Voidè solo un oggetto.
ony

1
@ OlivierJacot-Descombes: se voidfosse un tipo di valore vuoto, quell'istruzione si tradurrebbe in zero istruzioni per il codice macchina. Non molto utile per il tipo hardcoded di Void, ma utile nei casi in cui un tipo ha più parametri generici ma alcuni non sono necessari in alcuni casi.
supercat

2
@EricLippert: la corretta gestione dei valori di ritorno del tipo di valore richiederebbe la possibilità di estrarre un numero variabile di parole dallo stack. Ci sarebbe qualche difficoltà fondamentale nel permettere che il numero di parole fosse zero? Se il chiamante è responsabile dell'allocazione dello spazio e del passaggio di un byref, il sistema di tipi dovrebbe riconoscere che un byref vuoto non ha alcun significato, e forse questo non è stato considerato degno dello sforzo, ma non vedo alcun problema "fondamentale" .
supercat

9

Da: http://connect.microsoft.com/VisualStudio/feedback/details/94226/allow-void-to-be-parameter-of-generic-class-if-not-in-c-then-just-in- runtime

Questo in realtà è di progettazione - non consentiamo alcuna istanza del tipo vuoto (insieme a molti altri tipi in fase di esecuzione). Non puoi neanche creare un vuoto o un vuoto []. Abbiamo inserito questi buchi di tipo per sicurezza.

Non posso per la vita di me vedere quanto il vuoto sia un buco nella sicurezza, ma ... come dice.

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.