Mise à JOUR: Cette question a été l'objet de mon blog, le 20 septembre 2010. Merci pour la grande question!
Josh sez:
Cher M. Lippert, de nous Donner un scoop :)
Tout d'abord, tout ce que vous "bat signal" les gens: si il y a quelque chose que vous voulez porté à mon attention, vous pouvez toujours cliquer sur le lien "contact" sur mon blog.
Deuxièmement, mec, "M. Lippert" est mon père.
Josh et du Tchad réponses ("ils n'ajoutent pas de valeur alors pourquoi exiger d'eux?" et "pour l'élimination de la redondance") sont fondamentalement correcte. À la chair un peu plus:
La fonction de vous permettre d'éluder la liste des arguments dans le cadre de la "plus grande fonctionnalité" de initialiseurs d'objets rencontré notre bar pour "sucrés" caractéristiques. Certains points nous avons considéré:
- la conception et la spécification des coûts a été faible
- nous allions être largement modification de l'analyseur de code qui gère la création de l'objet, de toute façon; le coût de développement supplémentaire de faire la liste des paramètres de l'option n'a pas été grande par rapport à le coût de la plus grande fonctionnalité
- le test de charge a été relativement faible par rapport au coût de la plus grande fonctionnalité
- le fardeau de la documentation a été relativement faible par rapport...
- le fardeau de l'entretien a été prévu pour être petit; je ne me souviens pas de tous les bugs signalés dans cette fonctionnalité dans les années depuis qu'il est expédié.
- la fonction ne pose pas immédiatement évident risques pour les futures fonctionnalités dans ce domaine. (La dernière chose que nous voulons faire est de prendre un pas cher, facile fonctionnalité qui rend beaucoup plus difficile à mettre en oeuvre un intérêt dans l'avenir.)
- la fonction ajoute pas de nouvelles ambiguïtés de la lexicales, grammaticales ou l'analyse sémantique de la langue. Il ne pose pas de problèmes pour le genre de "partielle du programme" l'analyse effectuée par l'IDE "IntelliSense" moteur pendant que vous tapez. Et ainsi de suite.
- la fonctionnalité de frappe, une commune "sweet spot" pour l'ensemble de l'initialisation de l'objet; en règle générale, si vous utilisez un initialiseur d'objet c'est précisément parce que le constructeur de l'objet n'est pas de vous permettre de définir les propriétés que vous souhaitez. Il est très commun pour ces objets d'être tout simplement "sacs à la propriété" qui n'ont pas de paramètres dans le ctor en premier lieu.
Mise à JOUR: James demande dans un commentaire:
Pourquoi donc n'avez-vous pas aussi de faire des parenthèses vides en option dans le constructeur par défaut d'un objet de création d'expression que ne pas avoir un initialiseur d'objet?
Jetez un oeil à cette liste de critères ci-dessus. L'un d'eux est que le changement n'introduit pas de nouvelle de l'ambiguïté dans le lexique, de grammaire ou de l'analyse sémantique d'un programme. Votre changement proposé n' introduire une analyse sémantique de l'ambiguïté:
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
}
}
Ligne 1 crée une nouvelle C, appelle le constructeur par défaut, puis appelle la méthode d'instance M sur le nouvel objet. Ligne 2 crée une nouvelle instance de B. M et appelle son constructeur par défaut. Si les parenthèses sur la ligne 1 sont facultatifs puis ligne 2 d'être ambigu. Nous aurions alors à venir avec une règle la résolution de l'ambiguïté; on ne pouvait pas faire une erreur , car ce serait alors une modification de rupture qui change l'juridique existant programme C# dans un programme qui plante.
Par conséquent, la règle devrait être très compliqué: pour l'essentiel, que les parenthèses ne sont qu'une option dans les cas où ils ne sont pas d'introduire des ambiguïtés. Il faudrait analyser tous les cas de figure que d'introduire des ambiguïtés et ensuite écrire le code dans le compilateur pour les détecter.
Dans cette lumière, revenir en arrière et regarder tous les frais que je mentionne. Combien d'entre eux maintenant devenus grands? Règles compliquées ont la grande conception, spécification, développement, test et documentation frais. Les règles complexes sont beaucoup plus susceptibles de causer des problèmes avec les interactions inattendues avec des fonctionnalités dans le futur.
Tout cela pour quoi? Un petit avantage pour le client qui n'ajoute pas de nouveau pouvoir de représentation de la langue, mais n'ajoutez fou coin des cas, attendant juste pour crier "gotcha" à quelques malheureux qui se heurte à elle. Caractéristiques comme ça se couper immédiatement et de le mettre sur le "plus jamais cela".
Mise à JOUR: James demande à certains plus de questions de suivi, qui, pour moi, auteur des libertés avec:
Comment avez-vous déterminer cette ambiguïté?
Que l'on a été immédiatement clair, je suis assez familier avec les règles en C# pour déterminer quand un pointillé est attendue.
Lors de l'examen d'une nouvelle fonctionnalité, comment déterminez-vous si elle cause toute ambiguïté? Par contre, par la preuve formelle, par la machine d'analyse, de quoi?
Tous les trois. La plupart du temps nous il suffit de regarder la spécification et la nouille sur elle, comme je l'ai fait ci-dessus. Par exemple, supposons que nous voulions ajouter un nouveau préfixe de l'opérateur C#, appelé "frob":
x = frob 123 + 456;
"frob" ici, c'est comme "nouveau" ou "++" - il s'agit avant d'une expression quelconque. Nous aimerions travailler souhaité en priorité et associativité des opérateurs et ainsi de suite, et puis commencer à poser des questions comme "que faire si le programme a déjà un type, un champ, une propriété, un événement, une méthode, une constante ou local appelé frob?" Qui serait immédiatement conduire à des cas comme:
frob x = 10;
est-ce que signifie "faire le frob opération sur le résultat de x = 10, ou de créer une variable de type frob appelé x et affecter 10 pour elle?"
G(frob + x)
Est-ce à dire "frob le résultat de l'unaire opérateur plus sur x" ou "ajouter une expression frob x"?
Et ainsi de suite. Pour résoudre ces ambiguïtés, on risque d'introduire des méthodes heuristiques. Quand vous dites "var x = 10;" c'est ambigu; il pourrait signifier "inférer le type de x" ou elle pourrait signifier "x est de type var". Nous avons donc une heuristique: nous avons d'abord tenter de rechercher un type nommé var, et seulement si l'un n'existe pas ne nous en déduisons le type de x.
Ou, nous pourrions changer la syntaxe de sorte qu'il n'est pas ambigu. Quand ils ont conçu le C# 2.0-ils eu ce problème:
yield(x);
Que signifie le "rendement x dans un itérateur" ou "appel de la méthode du rendement avec l'argument x?" Par
yield return(x);
il est maintenant sans équivoque.
Dans le cas de l'option des parenthèses dans un initialiseur d'objet, il est nécessaire de raisonner sur de savoir si il y a des ambiguïtés introduit ou non, parce que le nombre de situations dans lesquelles il est permis d'introduire quelque chose qui commence par { est très faible. Fondamentalement, il suffit de différents déclaration des contextes, de l'instruction des lambdas, les initialiseurs de tableau et c'est à ce sujet. Il est facile de la raison, à travers tous les cas, et de montrer qu'il n'y a pas d'ambiguïté. Assurez vous que les IDE reste efficace est un peu plus difficile, mais peut être fait sans trop de difficultés.
Ce genre de bidouiller avec la spec est généralement suffisante. Si c'est un problème particulièrement compliqué caractéristique, puis nous nous retirons les outils plus lourds. Par exemple, lors de la conception de LINQ, un de le compilateur gars et celui de l'IDE gars qui ont un arrière-plan dans la théorie de l'analyseur construit un analyseur générateur qui pourrait analyser les grammaires de la recherche d'ambiguïtés, puis de la fed proposé C# grammaires pour la requête interprétations; ce faisant trouvé beaucoup de cas où les requêtes étaient ambiguës.
Ou, quand nous avons avancé l'inférence de type sur les lambdas en C# 3.0, nous avons écrit nos propositions et ensuite envoyées sur le bassin de Microsoft Research à Cambridge où les langues de l'équipe il y a bien assez de travailler jusqu'à une preuve formelle que l'inférence de type proposition a été théoriquement son.
Existe-il des ambiguïtés en C# d'aujourd'hui?
Assurez-vous.
G(F<A, B>(0))
En C# 1 c'est clair ce que cela signifie. C'est la même chose que:
G( (F<A), (B>0) )
C'est, il appelle G avec deux arguments qui sont des booléens. En C# 2, que pourrait signifier ce que cela signifiait en C# 1, mais cela pourrait également signifier "passer de 0 à la méthode générique de F qui prend des paramètres de type A et B, puis transmettre le résultat de F à G". Nous avons ajouté un complexe heuristique à l'analyseur qui détermine lequel des deux cas, vous probablement signifié.
De même, les castes sont ambigus, même en C# 1.0:
G((T)-x)
C'est que "la fonte de x à T" ou "soustraire x de T"? Encore une fois, nous avons une heuristique qui permet une bonne estimation.