Questa domanda è stata oggetto del mio blog il 20 settembre 2010 . Le risposte di Josh e Chad ("non aggiungono valore, quindi perché richiederle?" E "per eliminare la ridondanza") sono fondamentalmente corrette. Per arricchirlo un po 'di più:
La caratteristica di permettervi di elidere l'elenco degli argomenti come parte della "caratteristica più ampia" degli inizializzatori di oggetti ha incontrato la nostra barra per le caratteristiche "zuccherine". Alcuni punti che abbiamo considerato:
- il costo di progettazione e specifica era basso
- avremmo comunque modificato ampiamente il codice del parser che gestisce la creazione degli oggetti; il costo aggiuntivo di sviluppo per rendere opzionale l'elenco dei parametri non era elevato rispetto al costo della funzionalità più grande
- l'onere del test era relativamente piccolo rispetto al costo della funzionalità più grande
- l'onere della documentazione era relativamente piccolo rispetto ...
- si prevedeva che l'onere della manutenzione fosse ridotto; Non ricordo alcun bug segnalato in questa funzione negli anni trascorsi dalla sua spedizione.
- la funzionalità non pone rischi immediatamente evidenti per le funzionalità future in quest'area. (L'ultima cosa che vogliamo fare è creare una funzionalità facile ed economica ora che rende molto più difficile implementare una funzionalità più convincente in futuro.)
- la funzionalità non aggiunge nuove ambiguità all'analisi lessicale, grammaticale o semantica della lingua. Non pone problemi per il tipo di analisi del "programma parziale" che viene eseguita dal motore "IntelliSense" dell'IDE durante la digitazione. E così via.
- la caratteristica colpisce un comune "punto debole" per la caratteristica di inizializzazione di oggetti più grandi; tipicamente se stai usando un inizializzatore di oggetti è proprio perché il costruttore dell'oggetto non ti permette di impostare le proprietà che vuoi. È molto comune che tali oggetti siano semplicemente "borse di proprietà" che non hanno parametri nel ctor in primo luogo.
Perché allora non hai reso anche le parentesi vuote opzionali nella chiamata del costruttore predefinito di un'espressione di creazione di oggetti che non ha un inizializzatore di oggetto?
Dai un'altra occhiata all'elenco di criteri sopra. Uno di questi è che il cambiamento non introduce alcuna nuova ambiguità nell'analisi lessicale, grammaticale o semantica di un programma. La vostra proposta di modifica fa introdurre un'analisi ambiguità semantica:
class P
{
class B
{
public class M { }
}
class C : B
{
new public void M(){}
}
static void Main()
{
new C().M(); // 1
new C.M(); // 2
}
}
La riga 1 crea un nuovo C, chiama il costruttore predefinito e quindi chiama il metodo di istanza M sul nuovo oggetto. La riga 2 crea una nuova istanza di BM e chiama il suo costruttore predefinito.Se le parentesi sulla riga 1 fossero opzionali, la riga 2 sarebbe ambigua. Dovremmo quindi elaborare una regola che risolva l'ambiguità; non è stato possibile commettere un errore perché si tratterebbe di una modifica sostanziale che trasforma un programma C # legale esistente in un programma danneggiato.
Quindi la regola dovrebbe essere molto complicata: essenzialmente che le parentesi sono opzionali solo nei casi in cui non introducono ambiguità. Dovremmo analizzare tutti i possibili casi che introducono ambiguità e quindi scrivere codice nel compilatore per rilevarli.
In quella luce, torna indietro e guarda tutti i costi che ho menzionato. Quanti di loro ora diventano grandi? Le regole complicate hanno costi di progettazione, specifiche, sviluppo, test e documentazione elevati. È molto più probabile che le regole complicate causino problemi con interazioni impreviste con le funzionalità in futuro.
Tutto per cosa? Un piccolo vantaggio per il cliente che non aggiunge nuovo potere rappresentativo al linguaggio, ma aggiunge casi d'angolo pazzi che aspettano solo di gridare "gotcha" a qualche povera anima ignara che ci si imbatte. Funzionalità del genere vengono tagliate immediatamente e inserite nell'elenco "non farlo mai".
Come hai determinato quella particolare ambiguità?
Quello fu subito chiaro; Conosco abbastanza le regole in C # per determinare quando è previsto un nome puntato.
Quando si considera una nuova funzionalità, come si determina se causa ambiguità? A mano, con prove formali, con analisi automatiche, cosa?
Tutti e tre. Per lo più guardiamo solo le specifiche e la tagliatella, come ho fatto sopra. Ad esempio, supponiamo di voler aggiungere un nuovo operatore di prefisso a C # chiamato "frob":
x = frob 123 + 456;
(AGGIORNAMENTO: frob
è ovviamente await
; l'analisi qui è essenzialmente l'analisi che il team di progettazione ha eseguito durante l'aggiuntaawait
.)
"frob" qui è come "nuovo" o "++" - viene prima di un'espressione di qualche tipo. Calcolavamo la precedenza e l'associatività desiderate e così via, quindi iniziavamo a fare domande come "e se il programma avesse già un tipo, un campo, una proprietà, un evento, un metodo, una costante o un locale chiamato frob?" Ciò porterebbe immediatamente a casi come:
frob x = 10;
significa "fai l'operazione frob sul risultato di x = 10, o crea una variabile di tipo frob chiamata x e assegnale 10?" (Oppure, se frobbing produce una variabile, potrebbe essere un assegnamento di 10 a frob x
. Dopo tutto, *x = 10;
analizza ed è legale se lo x
è int*
.)
G(frob + x)
Significa "frob il risultato dell'operatore più unario su x" o "aggiungi espressione frob a x"?
E così via. Per risolvere queste ambiguità potremmo introdurre l'euristica. Quando dici "var x = 10;" è ambiguo; potrebbe significare "dedurre il tipo di x" o potrebbe significare "x è di tipo var". Quindi abbiamo un'euristica: prima tentiamo di cercare un tipo chiamato var, e solo se non esiste deduciamo il tipo di x.
Oppure potremmo cambiare la sintassi in modo che non sia ambigua. Quando hanno progettato C # 2.0 hanno riscontrato questo problema:
yield(x);
Significa "restituire x in un iteratore" o "chiamare il metodo yield con l'argomento x?" Modificandolo in
yield return(x);
ora è inequivocabile.
Nel caso di parentesi opzionali in un inizializzatore di oggetto è semplice ragionare sul fatto che ci siano ambiguità introdotte o meno perché il numero di situazioni in cui è consentito introdurre qualcosa che inizia con {è molto piccolo . Fondamentalmente solo vari contesti di istruzioni, espressioni lambda di istruzioni, inizializzatori di array e questo è tutto. È facile ragionare su tutti i casi e dimostrare che non c'è ambiguità. Assicurarsi che l'IDE rimanga efficiente è un po 'più difficile ma può essere fatto senza troppi problemi.
Questo tipo di armeggiare con le specifiche di solito è sufficiente. Se è una funzionalità particolarmente complicata, estraiamo strumenti più pesanti. Ad esempio, durante la progettazione di LINQ, uno dei ragazzi del compilatore e uno dei ragazzi dell'IDE che hanno entrambi un background nella teoria del parser si sono costruiti un generatore di parser che potrebbe analizzare le grammatiche alla ricerca di ambiguità, e quindi ha alimentato le grammatiche C # proposte per la comprensione delle query in esso ; in questo modo sono stati riscontrati molti casi in cui le query erano ambigue.
Oppure, quando abbiamo eseguito l'inferenza di tipo avanzata su lambda in C # 3.0, abbiamo scritto le nostre proposte e poi le abbiamo inviate a Microsoft Research a Cambridge, dove il team linguistico era abbastanza bravo da elaborare una prova formale che la proposta di inferenza di tipo fosse teoricamente sano.
Ci sono ambiguità in C # oggi?
Sicuro.
G(F<A, B>(0))
In C # 1 è chiaro cosa significa. È lo stesso di:
G( (F<A), (B>0) )
Cioè, chiama G con due argomenti che sono bool. In C # 2, ciò potrebbe significare cosa significava in C # 1, ma potrebbe anche significare "passare 0 al metodo generico F che accetta i parametri di tipo A e B, quindi passare il risultato di F a G". Abbiamo aggiunto una complicata euristica al parser che determina quale dei due casi probabilmente intendevi.
Allo stesso modo, i cast sono ambigui anche in C # 1.0:
G((T)-x)
È "cast -x to T" o "sottract x from T"? Di nuovo, abbiamo un'euristica che fa una buona ipotesi.