csharplang/meetings/2014/LDM-2014-05-07.md

6.3 KiB
Исходник Постоянная ссылка Ответственный История

C# Language Design Notes for May 7, 2014

Agenda

  1. protected and internal <feature cut – not worth the confusion>
  2. Field parameters in primary constructors <feature cut – we want to keep the design space open>
  3. Property declarations in primary constructors <interesting but not now>
  4. Typeswitch <Not now – more likely as part of a future more general matching feature>

protected and internal

Protected and internal was never a feature we were super enthusiastic about. The CLR supports it and it seemed reasonable to surface it in the language. However, the syntactic options are not great. For every suggestion there are significant and good reasons why it doesnt work. The community has been incredibly helpful in its creativity about names, as well as in pointing out their flaws.

Conclusion

We wont do this feature. Guidance for the scenarios it addresses will be to use internal: the most important aspect is to hide the member from external consumers of the assembly. The protected aspect is more of a software engineering thing within the team. You could imagine at some point adding the protected aspect as an attribute, either recognized by the compiler or respected by a custom diagnostic.

Field parameters in primary constructors

Now that weve added the initialization scope to classes, it is no longer a problem to have primary constructor parameters with the same name as members. This removes most of the motivation for having the field parameters feature, where an explicit accessibility modifier on a parameter would indicate that there should additionally be a field of that name.

Conclusion

As the next topic demonstrates, there are more interesting things to consider using this design space for in the future. Lets not occupy it now with this relatively unimportant feature. It is fine that people have to declare their fields explicitly.

Property declarations in primary constructors

While declaration of fields in the primary constructor parameter list is of limited value, it is very often the case that a constructor parameter is accompanied by a corresponding property. It might be nice if there was a shorthand for this. You could imagine very terse class declarations completely without bodies in some cases.

A hurdle here is the convention that parameters are camelCase (start with lower case) and public properties are PascalCase (start with upper case). To be general, wed need for each parameter to give not one but two names – something like this:

public class Point(int x: X, int y: Y);

Which would yield public getter-only properties named X and Y as well as constructor parameters x and y with which the properties are initialized. It would expand to this:

public class Point(int x, int y)
{
   public int X { get; } = x;
   public int Y { get; } = y;
}

This syntax looks fairly nice in the above example, but it gets a little unwieldy when the names are longer:

public class Person(string firstName: FirstName, string lastName: LastName);

Maybe we could live with not having separate parameter names. We could reuse the syntax weve just dropped for field parameters and use it for property parameters instead:

public class Person(public string FirstName, public string LastName);

This would be shorthand for writing

public class Person(string FirstName, string LastName)
{
   public string FirstName { get; } = FirstName;
   public string LastName { get; } = LastName;
}

Now the parameters would show up as PascalCase. This does not seem like a big deal for new types, but it would mean that most current code couldnt be moved forward to this syntax without breaking callers who use named arguments.

The implied association of parameter and property could certainly be useful in its own right. You could imagine allowing the use of object initializers to initialize these getter-only properties. Instead of translating it into setter calls, the compiler would know the corresponding constructor parameters to pass the values to:

var p = new Person { LastName = "Pascal", FirstName = "Blaise" };

Would turn into:

var p = new Person("Blaise", "Pascal");

Also, in the future, if we were to consider pattern matching or deconstruction features, this association could be helpful.

Conclusion

We like the idea of providing a shorthand in the primary constructor parameter list for generating simple corresponding properties. However, we are not ready to go down this route just yet. We need to decide on the upper-case/lower-case issue for one thing. We note that primary constructors already provide quite an improvement over what you have to write in C# 5.0. Thats just going to have to be good enough for now.

Typeswitch

For a long time weve had the idea to add a typeswitch feature to C#. In this coming release, VB is seriously looking at expanding its Select Case statement to allow matching on types. Syntactically, this seems to fit right in as a natural extension in VB. In C#, maybe not so much: the switch statement is quite restrictive and only a little evolved from Cs original jump table oriented design. It doesnt easily accommodate such a different form of case condition.

So if we were to add typeswitching capabilities to C#, we most likely would do it as a new feature with its own syntax. Options range from a switch-like construct with blocks for each match, to a more expression-oriented style reminiscent of pattern matching in functional languages.

A major point here is that type switching can be seen as a special case of pattern matching. Would we ever add generalized pattern matching to C#? It certainly seems like a reasonable possibility. If so, then we should think of any typeswitching feature in that light: it needs to have the credible ability to “grow up” into a pattern matching feature in the future.

Conclusion

Weve looked some at this, trying to imagine what a pattern matching future would look like. We have some great ideas, but we are not confident that we can map them out at this point to an extent where we would trust a current typeswitch design to fit well with it. And we do not have capacity to design and implement the full feature set in the current round.

Lets rather wait with the whole package and see if we can attack it in one go in the future.