C# Language Design Notes for May 7, 2014

Topics: C# Language Design
Coordinator
May 24, 2014 at 10:07 PM

C# Language Design Notes for May 7, 2014

Notes are archived here.

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 doesn’t work. The community has been incredibly helpful in its creativity about names, as well as in pointing out their flaws.

Conclusion

We won’t 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 we’ve 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. Let’s 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, we’d 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 we’ve 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 couldn’t 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. That’s just going to have to be good enough for now.

Typeswitch

For a long time we’ve 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 C’s original jump table oriented design. It doesn’t 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

We’ve 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.

Let’s rather wait with the whole package and see if we can attack it in one go in the future.
May 24, 2014 at 11:18 PM
Edited May 25, 2014 at 12:23 AM
TypeSwitch would have been nice to have when I implemented the C# version of StringFormat Diagnostic.

The C# part is more double the size of the VB.net version, that exploits this feature. Because I had implement it via if else if ...


Suggestion for pattern-matching.
match ( obj ) with
{
  case String
  case Integer
  case Boolean
}
Then make it feature compatible with vb.net Select Case
May 25, 2014 at 2:31 PM
Edited May 26, 2014 at 12:05 PM
Every primary constructor design makes me more sad.
Let's count the number of type/names mentions with various designs:
// original C# 3.0 design: 2*C + 2*T + 2*_t + 2*t + 2*u + 2*X
 
class C {
  private readonly T _t;
  public U X { get; set; }
 
  public C(T t, U u) {
    _t = t;
    X = u;
  }
}
 
 
// first design, implicit capture: 1*C + 1*T + 1*t + 2*U + 2*u + 1*X
 
class C(T t, U u) {
  public U X { get; set; } = u;
}
 
 
// second design, explicit capture: 1*C + 1*T + 1*t + 2*U + 2*u + 1*X
 
class C(private readonly T t, U u) {
   public U X { get; set; } = u;
}
 
 
// current design, everything explicit: 1*C + 2*T + 1*_t + 2*t + 2*u + 1*X
 
class C(T t, U u) {
  private readonly T _t = t;
  public U X { get; set; } = u;
}
So primary constructors now looks pretty useless.
Same number of type/name mentions as before, class declaration looks messy, there is no much syntax improvement at all.

First design with implicit capture was so much better ('class parameters' instead of 'fields').
You don't even need 'read-only auto-properties' feature with expression-bodied properties ('public string Name => name;').

Better to drop primary constructor feature at all, with current design this feature became more 'complexity' than 'benefit'.
May 25, 2014 at 4:41 PM
Yeah, I kind of agree. I don't even know what the use case is anymore. As syntax candy the benefit in terms of code reduction is minor, at best. At worst it complicates the body of the class by trying to cram logic somewhere it doesn't really belong all because for some reason it needs to be relatively on par feature-wise with normal constructors, which are far from complicated or verbose to write today.

I can see primary constructors being useful in formally declaring classes akin to anonymous-types, completely with immutability and equality comparison. I can see how that would work well with the proposals for pattern matching. But if their only goal is to reduce the one time that you retype the class name in the form of a constructor, that seems pointless. We already have named snippets in Visual Studio which eliminate that typing.
May 25, 2014 at 4:45 PM
Edited May 25, 2014 at 4:50 PM
madst wrote:
We note that primary constructors already provide quite an improvement over what you have to write in C# 5.0. That’s just going to have to be good enough for now.
Well, what is that improvement, exactly? As ControlFlow pointed out, the original design did have significant improvements, the current design mostly adds complexity without much benefit. So I absolutely agree with ControlFlow - primary constructors have been cut down so much that they're not really worth adding all the complexity to the language anymore. I also vote for dropping them. Add them once you have resolved the property/field declaration issue and once you know how the primary constructors should interact with a possible pattern matching feature in the future. It just doesn't seem right and feels somewhat rushed if you add them to C# 6.
May 25, 2014 at 5:17 PM
Can somebody explain me where is "quite an improvement" in this example:
class Person : Entity
{
  public string Name { get; }
  public int Age { get; }

  public Person(int id, string name, int age) : base(id)
  {
    if (name == null)
      throw new ArgumentNullException("name");
    if (age <= 0)
      throw new ArgumentOutOfRangeException("age");

    Name = name;
    Age = age;
  }
}

// =>

class Person(int id, string name, int age) : Entity(id)
{
  public string Name { get; } = name;
  public int Age { get; } = age;

  {
    if (name == null)
      throw new ArgumentNullException("name");
    if (age <= 0)
      throw new ArgumentOutOfRangeException("age");
  }
}
May 25, 2014 at 6:34 PM
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.
I do not see why this should be considered desirable. A public property is part of a type's "consumer" contract. To me, the type's body seems like the obvious place to declare those members. Why should part of the "consumer" contract be moved into the part of the contract that only "producers" should care about, i.e., the constructor declaration?
We note that primary constructors already provide quite an improvement over what you have to write in C# 5.0. That’s just going to have to be good enough for now.
I have to agree with ControlFlow here. What exactly is the improvement? You are proposing an alternative syntax for constructors, and I feel that if you are going to have two conflicting syntaxes meant to accomplish the same task, then there should be an exceptionally high standard applied in evaluating the benefits. I was not terribly thrilled with the earlier designs of primary constructors, but at least then there were some benefits. All I see now is an extra syntax that jumbles the member declarations around, and for all the added complexity, it offers only a meager reduction (if any) to the code footprint.

I urge you to eliminate primary constructors entirely and revisit the underlying reasons they were proposed in the first place. It seems to me that the primary use case was concise declaration of structural/tuple types. And if that is the case, then perhaps it would be better to focus on improving language support for tuple-like types specifically, rather than trying to bolt on a rather alien-feeling syntax to class declarations.
May 26, 2014 at 3:56 AM
Primary constructors-
I strongly believe you guys should consider the record syntax class Foo(String Bar); for C# 6.0. I think it's incredibly useful and is an important complement to the proposed primary constructors. I know personally this would save me a tremendous amount of code on almost a daily basis. I also think that if the field declaration shorthand syntax is being dropped, you need to have the shorthand property syntax to make the primary constructor more useful. I think the use of PascalCase for property and parameter name is fine.

Something like this would be terse, prevent any repetition and be mostly very clear:
class Foo(public String Bar, public int Baz)
{
    //I still think you should have some keyword to delimit the primary constructor body- I like "constructor"
    {
          //Presumably you could rewrite any primary constructor properties/parameter validation to directly check the backing field.
          if(Bar == null) throw new ArgumentNullException(nameof(Bar));
          if(Baz == null) throw new ArgumentNullException(nameof(Baz));
    }
}
@ControlFlow Of course it's easy to make examples where primary constructors are largely useless. They're not a one-size-fits-all sort of feature. I think the design really requires some of the features the team is deferring, like the shorthand property creation syntax, to be complete. It seems like the chicken is coming before the egg here, as the record syntax would benefit from primary constructor bodies to do argument validation.

I urge people to make design suggestions rather than asking for the feature to be entirely dropped. I think the fundamental pain point of this class requiring 13 lines in C# needs to be addressed:
class Point
{
     public int X {get; private set;}
     public int Y {get; private set;}
     public int Z {get; private set;}

    public Point(int x, int y, int z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}
Protected and internal-
It's very disappointing that this useful feature is being dropped from C# (but still will be present in VB) because of disagreement in the forums over the name. You guys should pick a name and go with it- you are never ever going to make 100% of people happy on an internet forum on any feature. Using an attribute would look like an ugly hack in my opinion. As I said in the other thread, restricted seems to be the least controversial; it has no pre-existing connotations to it so it forces the user to learn what it means.
May 26, 2014 at 8:31 AM
Edited May 26, 2014 at 8:31 AM
Just a note for this discussion, which is not on the main theme, but something to keep in mind.
You do not need constructor bodies for argument validation in current design.
class Person(int id, string name, int age) : Entity(id)
{
    public string Name { get; } = Argument.NotNull("name", name);
    public int Age { get; } = Argument.PositiveNonZero("age", age);
}
May 26, 2014 at 5:33 PM
MgSam wrote:
They're not a one-size-fits-all sort of feature. I think the design really requires some of the features the team is deferring, like the shorthand property creation syntax, to be complete. It seems like the chicken is coming before the egg here, as the record syntax would benefit from primary constructor bodies to do argument validation.
Indeed, I agree with the chicken v. egg problem. My opinion, though, is that if the extra design into these features that would really make primary constructors useful aren't on the table for C# 6.0 timeline that primary constructors be deferred until that time as well as fleshing out those features might change how they'd approach primary constructors. Otherwise we'd be stuck with whatever they do implement in C# 6.0, including that horrid initializer body syntax. I'd rather wait for the chicken than to be stuck with a bad egg. :)

In a given dictionary there are usually two definitions for the word "terse". One is "neatly concise and elegant" while the other is "rudely abrupt and curt". In my opinion, a language feature like primary constructors lies dangerously between the two.
Developer
May 26, 2014 at 10:48 PM
Edited May 26, 2014 at 10:49 PM
mstrobel wrote:
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.
I do not see why this should be considered desirable. A public property is part of a type's "consumer" contract. To me, the type's body seems like the obvious place to declare those members. Why should part of the "consumer" contract be moved into the part of the contract that only "producers" should care about, i.e., the constructor declaration?
The association between the parameter and the property enables the compiler to do a lot for you. These "primary properties" could be automatically used by the compiler to implement GeHashCode, Equals, and a pattern matching operator implementation (see the discussion of case classes and extractors in Matching Objects With Patterns by Emir, Odersky, and Williams). The pattern matching (or decomposition) operator can use the same parameter names as the primary constructor and produce values from the "corresponding" properties. There is some discussion about pattern matching on the VB language board, but it applies equally to VB and C#.
May 27, 2014 at 1:46 PM
Edited May 27, 2014 at 10:32 PM
Typeswitch:

If you allowed the case value to be an expression, you would have a much more powerful switch statement. The case evaluation would be similar to the try/catch evaluation -- the first case to match would be the one executed.
var command = Console.ReadLine();

switch(true)
{
    case command == "START":
        break;

    case command == "STOP":
        break;

    default:
        break;
}
or more directly to the Typeswitch discussion,
public void MyMethod(object o)
{
    switch(true)
    {
        case o is int:
            break;
        case o is string:
            break;
        case o is decimal:
            break;
        default:
            break;
    }
}
Validation could also be performed.
public void MyMethod(string Text)
{
    switch(true)
    {
        case string.IsNullOrEmpty(Text):
        case Text.Length > 20:
        case Text.Index("Q") > 1:
            throw new ArgumentException("Invalid Argument", "Text");
            break;
        default:
            break;
    }
}
May 27, 2014 at 4:43 PM
Edited May 27, 2014 at 4:45 PM
msauper wrote:
If you allowed the case value to be an expression, you would have a much more powerful switch statement. The case evaluation would be similar to the try/catch evaluation -- the first case to match would be the one executed.
C# and VB.NET take different approaches to their switch/case-style constructs. In C#, as in C, a switch construct is essentially evaluated as "take the value and determine from it an address to GOTO". Such determination may be performed using if/then logic, simple table lookups, hashed table lookups, or any of countless other techniques, at the discretion of the compiler. In VB.NET, a Select Case statement is semantically much closer to a bunch of if/then statements. This allows more versatility, but does not necessarily allow the same optimization opportunities as the C# construct. It would be possible that a VB.NET compiler could notice that all of the values tested for are constants, and implement C#-style optimization (I don't know if it does), but one potential concern with such an approach is that it's very easy for a piece of code which isn't a performance hot-spot to become one as a consequence of a subtle change elsewhere in the code. There can IMHO be significant value in being able to say "let me know if anything would prevent this piece of code from being implemented efficiently, so that if I decide to allow a potentially-inefficient implementation I'll know I need to ensure it doesn't become a performance hot spot".

I think a VB.NET-style Select Case statement would be a helpful addition to C#, but it might be a good idea to add a context-sensitive keyword to the switch statement so as to yield a new kind of statement.
May 27, 2014 at 6:32 PM
As for primary constructors, I have to agree with some of the objections I read here. For me, the primary use case is record types, that look exactly like anonymous types today.

In other words, when I say
var a = new { GivenName = "Kris", LastName = "Vandermotten" }
That generates a type as well as a constructor call.

I propose that
public class Name(string GivenName, string LastName);
(notice the absense of a { } body) generates the same type as the anonymous type above, with the obvious exceptions that 1) it has a name, and 2) I can specify visibility (not just internal as with anonymous types, but public as well. Instantiating would be done using
var a = new Name("Kris", "Vandermotten");
I personally don't care about the alternative syntax that uses an object initializer syntax, though it could be useful to convert existing anonymous type usage.

This being said, I do realize that anonymous types are implemented using generics today, and these record types should not use the same generics technique. But those differences are not observable in the language. I do want the same behavior for GetHashcode, Equals and ToString implementations, possibly with the addition of an IEquatable<T> implementation.

I also believe that other features could be added to this later, when the design is more clear, by allowing a { } body.
May 27, 2014 at 6:40 PM
As for type switching, I wonder whether you have considered something like this:
switch(obj.GetType())
{
    case typeof(string):
        // ...
        break;
    case typeof(int):
        // ...
        break;
}
In other words: the exact same syntax as for the existing switch, except that in addition to primitive types it would also allow switching on a type with case typeof(T):.

Just as with switching over a string or an int, a branch would only be taken in a type exactly matches, not when it is merely assignable (e.g. through inheritance or an implicit conversion).

If you did consider it, what were the objections?
Developer
May 27, 2014 at 6:57 PM
KrisVDM wrote:
As for type switching, I wonder whether you have considered something like this:
switch(obj.GetType())
{
    case typeof(string):
        // ...
        break;
    case typeof(int):
        // ...
        break;
}
In other words: the exact same syntax as for the existing switch, except that in addition to primitive types it would also allow switching on a type with case typeof(T):.

Just as with switching over a string or an int, a branch would only be taken in a type exactly matches, not when it is merely assignable (e.g. through inheritance or an implicit conversion).
That doesn't actually help with what you are likely trying to do in that code. If you try filling out the "..." sections, you'll see that you still have to insert casts in the code. Also, if-then-else works just as well.

The more general pattern-matching facility that I would like to see in some future language extension would accomplish that like this
switch (obj)
{
    case string s:
        // code using s
        break;
    case int i:
        // code using i
        break;
}
This is a special case of a more general pattern-matching facility.
May 27, 2014 at 7:23 PM
Edited May 27, 2014 at 7:32 PM
nmgafter wrote:
That doesn't actually help with what you are likely trying to do in that code. If you try filling out the "..." sections, you'll see that you still have to insert casts in the code. Also, if-then-else works just as well.
If-then-else actually doesn't work as well. First of all, it requires me to create a temp variable to hold the expression being switched over, to avoid repeated evaluation. A switch statement does not require that temporary (and if it does it hides it).

Secondly, a nested (or chained) if-then-else expresses an evaluation order, that must be honored by the language. A switch statement doesn't use Boolean expressions (as if statements do) and doesn't impose an evaluation order (because there is nothing to be evaluated for the cases - they're "literals"). That allows several optimizations that aren't necessarily possible with if-then-else.

I do realize that a cast would be required in most cases, but I don't consider that to be a problem. Note though that there certainly are cases where nothing would have to be cast. I might throw an exception for certain types, or the type might be a singleton (e.g. DBNull) for which I don't need to cast. In other cases, I may have to execute some specific code based on the type of the object, but not involving the object itself. I have seen something like that happening in logging code, where one line was logged based only on the type of the object, followed by a line that simply logged obj.ToString().

In fact, the usage of a Dictionary<Type, Action> is probably more equivalent with the syntax I asked about, than a chained if-then-else. But the proposed syntax is much cleaner and more readable, than setting up such a dictionary, and it avoids the delegates (and probably closures). This is especially true when cases fall through. For example:
switch(obj.GetType())
{
    case typeof(byte):
    case typeof(ushort):
    case typeof(uint):
    case typeof(ulong):
        throw new NotsupportedException("Unsigned types are not supported");
    case typeof(sbyte):
    case typeof(short):
    case typeof(int):
    case typeof(long):
        // do something that uses obj without casting, e.g. Console.Writeline(obj);
etc.
May 27, 2014 at 11:27 PM
Well, I think the 528 people who were interested enough to vote on this are going to find it very disappointing that the 'private protected' feature has now been withdrawn due to lack of agreement on a suitable syntax!

I see that, even though they did have a suitable syntax in the context of their language, it has also been withdrawn from VB without (apparently) there even being a design meeting to discuss it.

One thing on which there was general agreement was that we wanted this feature whatever it was called and Mads said as much.

So, as MgSam said, I do think that you guys should just pick a name and go with it. Everybody will soon get used it to whatever it is.

In fact, why not just go with private protected as you originally proposed? Since it doesn't use any new keywords, it has the least problems of all the suggestions. Also despite starting from a 'bad karma' position, it still managed 5th place in the poll and was 3rd in the least disliked list.

I do hope you guys will reconsider your position on this as it's definitely something which is worth implementing in both C# and VB, as it already is in C++/CLI.
May 28, 2014 at 5:19 AM
The switch statements do have an evaluation order.
Top to bottom, stop evaluation (and exit this level of switch) when a match is found
Otherwise continue, if none match goto case else.
May 28, 2014 at 1:40 PM
AdamSpeight2008 wrote:
The switch statements do have an evaluation order.
Top to bottom, stop evaluation (and exit this level of switch) when a match is found
Otherwise continue, if none match goto case else.
That may be true in VB (not sure), but it is not in C#. All cases are mutually exclusive, and their order doesn't matter. You can reorder them at will, without any semantic difference. That is what allows the jump table optimization.
May 28, 2014 at 5:05 PM
primary constructors
I wholeheartedly agree with KrisVDM:
As for primary constructors, I have to agree with some of the objections I read here. For me, the primary use case is record types, that look exactly like anonymous types today.

[skipped]
I propose that
public class Name(string GivenName, string LastName);
(notice the absense of a { } body) generates the same type as the anonymous type above, with the obvious exceptions that 1) it has a name, and 2) I can specify visibility (not just internal as with anonymous types, but public as well. Instantiating would be done using
var a = new Name("Kris", "Vandermotten");
I personally don't care about the alternative syntax that uses an object initializer syntax, though it could be useful to convert existing anonymous type usage.

This being said, I do realize that anonymous types are implemented using generics today, and these record types should not use the same generics technique. But those differences are not observable in the language. I do want the same behavior for GetHashcode, Equals and ToString implementations, possibly with the addition of an IEquatable<T> implementation.

I also believe that other features could be added to this later, when the design is more clear, by allowing a { } body.
IMHO the examples initially selected to illustrate this feature are misleading - I don't think many programmers are not willing to write 13 lines of code for the Person class.
I believe the problem is that one has to write more than 60 lines of code to implement ObscureUsedOnlyOnceFunctionResult class which has the sole purpose to name string and int returned from that function. It is literally more than 60 lines as it has to include mandatory comment (by company standard). MgSam have provided a nice example in the VB discussion.

Personally I see such classes written weekly and although Tuple can eliminate this waste, the lack of names is a significant drawback especially as these are rarely used functions. It is also a regular source of errors as people routinely elect not to implement GetHashcode or Equals and then somebody tries to use a Dictionary.

I think if this scenario can be optimized to:
public class ObscureUsedOnlyOnceFunctionResult(string Name, int BestScore);
public ObscureUsedOnlyOnceFunctionResult ObscureUsedOnlyOnceFunction(string game);
It would be perfect improvement where it matters.

I would also like it to be optionally anonymous and signature typed, for something like this to be legal:
    public class(string Name, int BestScore) ObscureUsedOnlyOnceFunction(string game);
       if((var x=ObscureUsedOnlyOnceFunction(game)).BestScore>100)
    //... and then in another file ...
    public class LeaderBoardEntry(string Name, int BestScore);
    List<LeaderBoardEntry> leaderBoard;
      leaderBoard.Add(ObscureUsedOnlyOnceFunction(game));
But if we can reduce 60 lines of code to 6 (counting comments), the removal of another 3 lines is by far less important.
May 29, 2014 at 11:56 AM
I'm very happy with the decisions you've made here. The field initializers never looked natural to me. I think by being conservative you can make sure that future changes aren't hobbled by hastly made decisions now. I expect once out in the wild, the features you are adding will lead people towards more functional coding styles which can then drive future changes.

I look forward to a record-type syntax in the future, but for now the improvements when creating immutable classes are great.
May 29, 2014 at 4:25 PM
alexdrel wrote:
I would also like it to be optionally anonymous and signature typed, for something like this to be legal:
```C#
public class(string Name, int BestScore) ObscureUsedOnlyOnceFunction(string game);
I don't like the declaration syntax, but if language-design teams could agree upon a standard naming convention for such types [so that such types would be interoperable between languages] they could be helpful. Unfortunately, the most efficient kind of type for such usage (a simple exposed-field aggregate) is despised by some influential people, notwithstanding the fact that if the compiler's return value were an accessible temporary, code like:
public {string Name, int BestScore} SomeFunction()
{
  return.Name = "Fred";
  return.BestScore = 123456;
}

...
var temp=SomeFunction();
DoSomething(temp.Name, temp.BestScore);
could be even more efficient than:
public SomeFunction(out string Name, out int BestScore)
{
  Name = "Fred";
  BestScore = 123456;
}

...
string name;
int bestScore;
SomeFunction(out name, out bestScore);
DoSomething(name, bestScore);
[functions which return structures are invoked by having the caller pass a byref to a location where the function should put the return; in the former code, the caller could pass a single byref--to temp--which the called method would then write to directly; the latter approach would require passing two byrefs rather than one, using an "immutable" structure type would generally necessitate additional copying operations, and an immutable class would require a heap allocation as well.
Jun 3, 2014 at 2:15 PM
Edited Jun 3, 2014 at 2:22 PM
To recap my earlier statement:
It seems to me that the primary use case was concise declaration of structural/tuple types. And if that is the case, then perhaps it would be better to focus on improving language support for tuple-like types specifically, rather than trying to bolt on a rather alien-feeling syntax to class declarations.
The more recent comments by @KrisVDM and @axeldreal seem to concur, and their proposal for a simple, one-line record type declaration is pretty much exactly what I was going to propose:
  1. Get rid of primary constructors for arbitrary classes. This eliminates the clumsiness of having two syntaxes for constructors, the horrible "anonymous block" syntax for primary constructor bodies, and the lingering questions of how to bind field/property declarations (for which I have seen no good answers).
  2. Implement support for named record types, in a similar vein to anonymous types in C# 3.0, and including generation of Equals(), GetHashCode(), and ToString().
The syntax proposed by @KrisVDM seems to fit the bill nicely:
public class Name(string GivenName, string LastName);
It might be nice if we could replace class with record to further distinguish these definitions from "regular" classes, but adding keywords can be problematic.

I would argue that this solution offers more benefits than the current proposal for primary constructors, in that it actually allows for a substantial reduction in code footprint for a common use case.
Jun 3, 2014 at 4:28 PM
MgSam wrote:
I urge people to make design suggestions rather than asking for the feature to be entirely dropped. I think the fundamental pain point of this class requiring 13 lines in C# needs to be addressed:
class Point
{
     public int X {get; private set;}
     public int Y {get; private set;}
     public int Z {get; private set;}

    public Point(int x, int y, int z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}
How about this one:
class Point
{
    public initonly property int X, Y, Z;
}

var point = new Point { X = 100, Y = 200, Z = 300 };
By introducing two new keywords, initonly and property, code can be much shorter and easier to read. Unlike readonly properties, initonly ones can be called within object initializers.
Jun 3, 2014 at 4:48 PM
How often are you going to implement a point class? Maybe once or twice. Of which 13 lines is very small cost to pay.
Jun 3, 2014 at 5:27 PM
Edited Jun 3, 2014 at 5:28 PM
AdamSpeight2008 wrote:
How often are you going to implement a point class? Maybe once or twice. Of which 13 lines is very small cost to pay.
This is why I see little point in having primary constructors on arbitrary classes. Day to day, the average developer is going to be spending very little time--if any--writing the kinds of custom data structures that this feature is intended to optimize. The one significant exception seems to be for simple 'record' types, which is why I suggest optimizing for those types specifically.
Jun 3, 2014 at 7:55 PM
I just want to say that I would gladly trade each and every C# 6.0 feature discussed so far for tuple syntax and pattern matching.
Jun 3, 2014 at 9:46 PM
I'm a little disappointed that field parameters are gone. I have tons of classes in my daily code that looks like that
public class Service
{
    private ISomeInterfaceWithLongName someInterfaceWithLongName = null;

    private IOtherInterfaceGeneric<IOtherService> otherInterfaceGeneric = null;

    public Service(ISomeInterfaceWithLongName someInterfaceWithLongName, IOtherInterfaceGeneric<IOtherService> otherInterfaceGeneric)
    {
        this.someInterfaceWithLongName = someInterfaceWithLongName;
        this.someInterfaceWithLongName = otherInterfaceGeneric;
    }
}
I have classes like this everywhere and of course they are created by use of DI contaner. Primary constructor with field parameters was the "little nice feature" that would made my code a little cleaner. Now I don't see many use cases for this feature (in my code).

I agree with others that "record" types (which are basically the same as anonymous types but with names) are much more needed. The proposed syntax (public class Name(string GivenName, string LastName);) looks good to me. It would be great to create structs that way too. Using initializer syntax is great to. Looks almost like anonymous types creation syntax. I would even propose to made it the ony one syntax (without the normal constructor syntax), so field names would be always visible in calling code.

To sum up, support for easy to write immutable record types is really welcome and would be one of the most used new feature of the language.
Jun 3, 2014 at 10:28 PM
AdamSpeight2008 wrote:
How often are you going to implement a point class? Maybe once or twice. Of which 13 lines is very small cost to pay.
I would say that even once is one too many. But day to day people in the industry are "designing" classes just to aggregate a few fields and it is not 13 lines - please, please include comments in the count, additional file (one class per cs file policy) and expanded project that could not fit into the screen height.
I believe tuples with names are must this day, look at "brand new" but generally uninspiring Swift - they have it.

The immutability of data structures has so many benefits, it should be promoted by making it easier to write:
public readonly class ObscureUsedOnlyOnceFunctionResult { string Name; int BestScore; }
return new ObscureUsedOnlyOnceFunctionResult { Name="Kvothe", BestScore=int.MaxValue };
Adding readonly and skipping class body would reduce compatibility risks and make the intent explicit. Automatic generation of Equals(), GetHashCode(), and ToString() (although I personally hate it) would be performed for new readonly classes only, which also mitigates compatibility concerns.

Although the discarded syntax with readonly works OK for me:
public readonly class ObscureUsedOnlyOnceFunctionResult(string name: Name, int BestScore);
I do not think it provides additional value w/o class body.

This will give us named "tuple" with names :), but I still want unnamed tuple with names - TypeScript can do it.
In this case both "readonly" and "class" has to be assumed not to have parser to look ahead and the visibility inherited from the function itself:
public { string Name; int BestScore; } ObscureUsedOnlyOnceFunction = () => new { Name="Kvothe", BestScore=int.MaxValue };
// is much more readable and self-documented than
public Tuple<string, int> ObscureUsedOnlyOnceFunction = () => new Tuple<string,int>("Kvothe", int.MaxValue); 
As for the interop with other .net languages it may indeed be implemented internally as a tuple, so names will be usable only in C# and everybody else will see it as generic Tuple, I guess the same trick worked rather well for dynamic.
Jun 3, 2014 at 11:06 PM
alexdrel wrote:
The immutability of data structures has so many benefits, it should be promoted by making it easier to write:
What's needed is not so much to facilitate immutability, but rather to facilitate working with values as opposed to entities [the distinction being that if a variable is used to encapsulate a value, its state should not change outside the control of the class or code that owns the variable in question]. There are four ways in .NET by which a field can encapsulate a value:

-1- Use a struct

-2- Use a freely-shareable reference to an object that won't allow anyone to modify it.

-3- Use a reference to an object which holders are forbidden from modifying or sharing with anyone who might.

-4- Use a reference to an object which is never exposed outside the control of the owner.

While it's easy to share values using immutable object, it's often difficult to work with them efficiently. Conversely, mutable objects make it easy to work with values, but difficult to share them. Exposed-field structs allow reasonably efficient manipulation and sharing, but have some severe limitations. What is needed IMHO is a means not just of creating form #2, but efficiently converting data among the different forms.
Jun 4, 2014 at 1:53 AM
Property declarations in primary constructors
May be it can still make it?
I just look at real code example at: http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.CSharp/Declarations/RootSingleNamespaceDeclaration.cs
It is 71 lines for the class itself. Combined with `readonly' and renaming syntax it can be reduced to 16:
    internal readonly sealed class RootSingleNamespaceDeclaration(
            bool HasUsings: public override,
            bool HasExternAliases: public override,
            SyntaxReference treeNode,
            ImmutableArray<SingleNamespaceOrTypeDeclaration> children,
            ImmutableArray<ReferenceDirective> referenceDirectives: public ReferenceDirectives,
            ImmutableArray<Diagnostic> referenceDirectiveDiagnostics: public ReferenceDirectiveDiagnostics,
            bool HasAssemblyAttributes: public)
            :  SingleNamespaceDeclaration(string.Empty,
                   treeNode,
                   nameLocation: new SourceLocation(treeNode),
                   children: children)
    {
        Debug.Assert(!referenceDirectives.IsDefault);
        Debug.Assert(!referenceDirectiveDiagnostics.IsDefault);
    }
Beside wasting a finite number of keystrokes, the repetitiveness unfortunately became synonymous to production quality as oppose to toy scripting language. I feel that this is plain wrong.
Jun 4, 2014 at 2:30 AM
Interestingly, Apple's Swift has this concept of internal vs external names for function parameters that feels very similar to the parameter vs property name concept the language design committee explored above. In considering this further, I think providing separate names is a good idea as long as its optional, as it is in Swift. This lets you write concise definitions for new types, and for old types that you want to move forward you have an upgrade path to do so.

I've also been considering an important issue surrounding the proposed record types- what if you want a record with just a tad bit more functionality. Should you lose the auto-implementation of GetHashCode, Equals, and ToString just because you define a class body?

For example:
class Person(String FirstName, String LastName);
Oh wait, I actually need a FullName property too:
class Person(String FirstName, String LastName)
{
    public String FullName { get { return FirstName + " " + LastName; } }
    //But now no more auto-implementing of GetHashCode, Equals, ToString?
}
For this reason, I think a record keyword would actually be useful. I think it's purpose would be to indicate any class or struct with it gets their GetHashCode, Equals, and ToString auto-implemented by the compiler unless they are explicitly overridden.
record class Person(String FirstName, String LastName)
{
    public String FullName { get { return FirstName + " " + LastName; } }
    // Now I get GetHashCode, Equals, and ToString for free still
}
This functionality is really orthogonal to property shorthand syntax when it comes down to it, and it could greatly benefit existing classes that don't use any other C# 6.0+ features.
Jun 4, 2014 at 8:41 AM
I think automatic implementation of GetHashCode and Equals should not be bound to any other feature. I would like it working for regular class or struct as well. What I think, there should be a way to annotate fields and properties with keyword or attribute and compiler should pick them and generate these methods using annotated members.
// initialization, ctors and other stuff omitted for brevity:
class MyClass
{
  // these fields would be used by compiler to generate GetHashCode and Equals
  readonly int identity myField;
  public string identity Name { get; private set; }

  // these field would not be used by compiler in its automatic GetHashCode and Equals
  readonly int myOtherField
}
or:
class MyClass
{
  // these fields would be used by compiler to generate GetHashCode and Equals
  readonly int [Identity] myField;
  public string [Identity] Name { get; private set; }

  // these field would not be used by compiler in its automatic GetHashCode and Equals
  readonly int myOtherField
}
There could be error if there are annotated members and overriden GetHashCode/Equals at the same time. Or when you have annotated static member.
There could be warning when you annotate mutable field or property - like public not-readonly field or property with not-private setter

This way Equals and GetHashCode could be implemented automatically for any type. Your record type could be handled by compiler in a way where all generated fields / properties are properly annotated and thus get Equals and GetHashCode methods.

As for ToString implementation - I think it is completely another pair of shoes.
Jun 4, 2014 at 8:10 PM
MgSam wrote:
Interestingly, Apple's Swift has this concept of internal vs external names for function parameters that feels very similar to the parameter vs property name concept the language design committee explored above.
External/internal names in Swift is not a 'feature', this is a thing to simplify Objective-C interop (where most of parameters passed with naming convention like withX: / withHeight:).
Jun 4, 2014 at 8:15 PM
ControlFlow wrote:
External/internal names in Swift is not a 'feature', this is a thing to simplify Objective-C interop (where most of parameters passed with naming convention like withX: / withHeight:).
Not sure why that matters to the discussion. And yes it is a feature. Are named parameters not a "feature" of C# because they were added largely with Office interop in mind? I read the language docs and I didn't see any mention of "don't use this feature unless you're trying to interop with Objective C".

Again though, I'm not sure this thread is the appropriate place to discuss Swift.
Jun 4, 2014 at 8:47 PM
I concur with the general sentiment that primary constructors are simply not worth the bother if there's no way to concisely map parameters to fields or properties (preferably properties!).
Jun 5, 2014 at 5:20 PM
Is a similar list for decisions regarding VB available?
Jun 5, 2014 at 6:31 PM
The more I read here, the more I am convinced about my proposed bodyless syntax for record types.
public class Name(string FirstName, string LastName);
Like others have said as well, the primary goal is to have simple syntax for named tuples, named anonymous types, aggregate types, DTO's or record types, whatever you want to call them.

What defines these types is the primary constructor syntax, not so much the absence of the body. The reason I propose the absence of a body, is that the body could turn out to be a can of worms we don't want to open just yet. But more importantly: if you want to write a full fledged type with all the whistles and bells, we do have syntax for that already.

So I propose the following syntax:
record-declaration:
    attributes(opt) record-modifiers(opt) 'class'|'struct' identifier type-parameter-list(opt) '(' record-property-declarations(opt) ')' type-parameter-constraints-clauses(opt) ';'

record-modifiers:
    record-modifier
    record-modifiers record-modifier

record-modifier
    'public'
    'internal'

record-property-declarations
    record-property-declaration
    record-property-declarations ',' record-property-declaration

record-property-declaration
    type identifier
As you can see, this syntax is very simple, even to the point you could say restrictive. But again, we already have an unrestricted syntax. Let's go over this syntax:

attributes(opt): just like attributes applied to a class a struct today. Could be useful for [Serializable] for example

record-modifiers: All we need is public or internal visibility. static and abstract make no sense. Record classes would be automatically sealed, so no need to mention it (and hence no support to name a base class).

record-property-declaration: Just a type followed by an identifier. No attributes (which avoids discussions about what they apply to: the constructor parameter or the property). No static (all instance properties), no readonly (getter-only properties), no ref or out. Not even default values, just to keep it simple.

type-parameter-list(opt) and type-parameter-constraints-clauses(opt) as defined in the C# 5.0 specification. I see no reason not to allow them, so why not.

And indeed no body. I admit additional members might be useful, but they raise all kinds of questions we don't need to be raised, and we already have syntax for them. This also implies that primary constructors on normal classes or structs with a body would not be allowed.

These types would auto-implement GetHashCode(), Equals(object) and ToString(), much like anonymous types do today and in a way compatible with their implementation. That would allow easy refactoring of anonymous types into (named) record types, without much risk of introducing subtle bugs in existing programs. I'm still in doubt about implementing IEquatable<T>, which is especially useful for structs (to avoid boxing).

I believe this meets a real need, can significantly improve readability and productivity (especially when writing in a functional style), is not blocking further evolution (e.g. usage for pattern matching, adding bodies to record types later on, ...) and should be a lot cheaper to build than the current proposals for primary constructors. This feature just has a very good benefit for cost ratio.
Jun 5, 2014 at 6:34 PM
I should have read that again before posting. Obviously, there is no need for record-modifiers. One record-modifier(opt) suffices, as public and internal are mutually exclusive. The default would of course be internal.
Jun 5, 2014 at 7:15 PM
KrisVDM wrote:
I should have read that again before posting. Obviously, there is no need for record-modifiers. One record-modifier(opt) suffices, as public and internal are mutually exclusive. The default would of course be internal.
I do like the idea of combining it with property expressions so a record type could have read-only calculated members. They would not affect the type's identity or equality.

E.g.
public class Rectangle (int Width, int Height)
{
    public int Area => Width * Height;
}
If we were to get into pattern matching I don't know that said members would participate, but it could be nice.
Jun 5, 2014 at 7:32 PM
Edited Jun 5, 2014 at 7:37 PM
Halo_Four wrote:
I do like the idea of combining it with property expressions so a record type could have read-only calculated members. They would not affect the type's identity or equality.
If we were to get into pattern matching I don't know that said members would participate, but it could be nice.
To be honest, I did consider them, but are they really that useful? There is an easy and concise alternative: an extension method.

You're already lifting the lid of the can of worms: they wouldn't participate in equality and hashing, but what about in ToString()? Or, like you said, in future pattern matching? What if someone wrote public int SomeProperty => new Random().Next();? My proposed syntax ensures that these record types are immutable (provided the types of their properties are as well). Let's keep Pandora's box closed for now.
Jun 5, 2014 at 8:25 PM
KrisVDM wrote:
Halo_Four wrote:
I do like the idea of combining it with property expressions so a record type could have read-only calculated members. They would not affect the type's identity or equality.
If we were to get into pattern matching I don't know that said members would participate, but it could be nice.
To be honest, I did consider them, but are they really that useful? There is an easy and concise alternative: an extension method.

You're already lifting the lid of the can of worms: they wouldn't participate in equality and hashing, but what about in ToString()? Or, like you said, in future pattern matching? What if someone wrote public int SomeProperty => new Random().Next();? My proposed syntax ensures that these record types are immutable (provided the types of their properties are as well). Let's keep Pandora's box closed for now.
Extension methods are a pain to add to a new class you're writing. And they have their own scopes separate from the class. I think making auto-implementation of GetHashCode, Equals, etc distinct from the "record" type shorthand class Foo(int Bar); makes both features much more versatile.
Jun 5, 2014 at 9:38 PM
Edited Jun 5, 2014 at 9:39 PM
MgSam wrote:
I think making auto-implementation of GetHashCode, Equals, etc distinct from the "record" type shorthand class Foo(int Bar); makes both features much more versatile.
Auto-implementation of equality-testing methods is complicated by the fact that there are two different equality relations a class may want to ask an encapsulated object about:
  1. Have you always been, and will you always be, equivalent to the object identified by a particular reference, so long as both you and the object identified by that reference exist, even if references to you and/or the other object are exposed to the outside world?
  2. Will your state be equivalent to that of the object identified by a particular reference, at least until the next time either you is asked to change it?
The first question is generally more useful when applied to mutable objects and is meaningless when applied to structures; the second is more useful when applied to structures or immutable objects. Unfortunately, while it is very common to produce immutable instances of mutable classes by creating new instances and encapsulating them such that they'll never be exposed to code that can change them, there is no standard way by which an encapsulating class can ask the encapsulated instance to answer the second question rather than the first.

It would not be difficult to design an object-oriented model which was quite similar to .NET, and kept all of its advantages relative to the C++ model with all its copy constructors etc., but allowed code to distinguish (as C++ does) between variables which encapsulate value and those which identify entities. Under such a model, auto-generated code could handle most common cases of equality testing, hashing, cloning, and even an thread-agnostic variation of copy-on-write [each object would be created as either immutable and shareable, or unsharable but mutable; this wouldn't eliminate quite as many redundant copy operations as some other copy-on-write schemes, but would eliminate the need for the interlocked memory operations which generally kill the performance of COW schemes]. Unfortunately, integrating such distinctions into the existing Framework would be difficult.
Jun 6, 2014 at 7:56 AM
supercat wrote:
Auto-implementation of equality-testing methods is complicated by the fact that there are two different equality relations a class may want to ask an encapsulated object about:
  1. Have you always been, and will you always be, equivalent to the object identified by a particular reference, so long as both you and the object identified by that reference exist, even if references to you and/or the other object are exposed to the outside world?
  2. Will your state be equivalent to that of the object identified by a particular reference, at least until the next time either you is asked to change it?
For reference types, the first is called reference equality (the == operator) and the second is called value equality (the Equals method). For value types, only the second makes sense.

Anyway, this problem has been solved already for anonymous types.
Jun 6, 2014 at 5:48 PM
KrisVDM wrote:
For reference types, the first is called reference equality (the == operator) and the second is called value equality (the Equals method). For value types, only the second makes sense.

Anyway, this problem has been solved already for anonymous types.
The problem is largely solved except for the very common case where code holds a reference to something which it knows is never going to change, but the thing to which it holds a reference has no way of knowing that. As a simple example, suppose a type ArrayHolder has a single field of type int[]; two instances hold references to separate arrays, each holding {1,2,3}. If neither array will ever be modified, then the class instances should consider themselves equal since content. Otherwise they should consider themselves unequal. The array class has no way of knowing whether a particular instances might be modified, but ArrayHolder might know that it won't be. If the virtual Equals and HashCode methods contained a bool argument AssumeImmutable, then Array could implement Equals to test sequence equality when AssumeImmutable is true, and reference equality when false.

Now suppose that ArrayHolder has an indexed property which could write the array, but some other class ImmutableArrayWrapper includes a field of ArrayHolder which identifies an instance that it itself created or received from code that promised never to modify it, and it never calls the property setter nor exposes the reference to any code that might do so. In that case, int[] wouldn't know whether a given instance is mutable or not, and ArrayHolder likewise, but ImmutableArrayWrapper would know that the particular instance of ArrayHolder which it holds will never have any mutating methods called on it, and that instance in turn will know that if none of its mutating methods are called, the int[] to which it holds a reference won't be modified either, and thus those array instances should be tested for sequence equality. While it would be possible for ImmutableArrayWrapper to perform a sequence-equality check itself, such a test could be more efficiently performed by int[], if it had some way of knowing such a test was required.