This project is read-only.

C# Language Design Notes for Apr 21, 2014 (Part I)

Topics: C# Language Design
Apr 30, 2014 at 4:35 PM
Edited Apr 30, 2014 at 6:53 PM

C# Language Design Notes for Apr 21, 2014

Notes are archived here.

This is Part I. Part II is here and Part III is here.

Agenda

In this design meeting we looked at some of the most persistent feedback on the language features showcased in the BUILD CTP, and fixed up many of the most glaring issues.
  1. Indexed members <lukewarm response, feature withdrawn>
  2. Initializer scope <new scope solves all kinds of problems with initialization>
  3. Primary constructor bodies <added syntax for a primary constructor body>
  4. Assignment to getter-only auto-properties from constructors <added>
  5. Separate accessibility for type and primary constructor <not worthy of new syntax>
  6. Separate doc comments for field parameters and fields <not worthy of new syntax>
  7. Left associative vs short circuiting null propagation <short circuiting>

Indexed members

The indexed member feature – e.$x and new C { $x = e } – has been received less than enthusiastically. People aren’t super happy with the syntax, but most of all they aren’t very excited about the feature.

We came to this feature in a roundabout way, where it started out having much more expressiveness. For instance, it was the way you could declaratively create an object with values at given indices. But given the dictionary initializer syntax – new C { ["x"] = e } – the $ syntax is again just thin sugar for using string literals in indexers. Is that worth new syntax? It seems not.

Conclusion

We’ll pull the feature. There’s little love for it, and we shouldn’t litter the language unnecessarily. If this causes an outcry, well that’s different feedback, and we can then act on that.

Initializer scope

There are a couple of things around primary constructors and scopes that are currently annoying:
  1. You frequently want a constructor parameter and a (private) field with the same name. In fact we have a feature just for that – the so-called field parameters, where primary constructors annotated with an accessibility modifier cause a field to be also emitted. However, if you try to declare this manually, we give an error because members and primary constructor parameters are in the same declaration space.
  2. We have special rules for primary constructor parameters, making it illegal to use them after initialization time, even though they are “in scope”.
So in this code:
public class ConfigurationException(Configuration configuration, string message) 
    : Exception(message)
{
    private Configuration configuration = configuration;
    public override string ToString() => message + "(" + configuration + ")";
}
The declaration of the field configuration is currently an error, because it clashes with the parameter of the same name in the same declaration space, but it would be nice if it just worked.

The use of message in a method body is and should be an error, but it would be preferable if that was a more natural consequence of existing scoping rules, instead of new specific restrictions.

An idea to fix this is to introduce what we’ll call the initialization scope. This is a scope and declaration space that is nested within the type declaration’s scope and declaration space, and which includes the parameters and base initializer arguments of a primary constructor (if any) and the expressions in all member initializers of the type.

That immediately means that this line becomes legal and meaningful:
    private Configuration configuration = configuration;
The field configuration no longer clashes with the parameter configuration, because they are no longer declared in the same declaration space: the latter’s is nested within the former’s. Moreover the reference to configuration in the initializer refers to the parameter, not the field, because while both are in scope, the parameter is nearer.

Some would argue that a line like the above is a little confusing. You are using the same name to mean different things. That is a fair point. The best way to think of it is probably the corresponding line in a normal constructor body:
    this.configuration = configuration;
Which essentially means the same thing. Just as we’ve gotten used to this disambiguating that line, we’ll easily get used to the leading modifier and type of the field declaration disambiguating the field initializer.

The initialization scope also means that this line is naturally disallowed:
    public override string ToString() => message + "(" + configuration + ")";
Because the reference to message does not appear within the initialization scope, and the parameter is therefore not in scope. If there was a field with that name, the field would get picked up instead; it wouldn’t be shadowed by a parameter which would be illegal to reference.

A somewhat strange aspect of the initialization scope is that it is textually discontinuous: it is made up of bits and pieces throughout a type declaration. Hopefully this is not too confusing: conceptually it maps quite clearly to the notion of “initialization time”. Essentially, the scope is made up of “the code that runs when the object is initialized”.

There are some further desirable consequences of introducing the initialization scope:

Field parameters

The feature of field parameters is currently the only way to get a primary constructor parameter and a field of the same name:
public class ConfigurationException(private Configuration configuration, …)
With the initialization scope, the feature is no longer special magic, but just thin syntactic sugar over the field declaration above. If for some reason field parameters don’t work for you, you can easily fall back to an explicit field declaration with the same name as the parameter.

It raises the question of whether we’d even need field parameters, but they still seem like a nice shorthand.

The scope of declaration expressions in initializers

In the current design, each initializer provides its own isolated scope for declaration expressions: there was no other choice really. With the initialization scope, however, declaration expressions in initializers would naturally use that as their scope, allowing the use of locals to flow values between initializers. This may not be common, but you can certainly imagine situations where that comes in handy:
public class ConfigurationException(Configuration configuration, string message) 
    : Exception(message)
{
    private Configuration configuration = configuration;
    public bool IsRemote { get; } = (var settings = configuration.Settings)["remote"];
    public bool IsAsync { get; } = settings["async"];
    public override string ToString() => Message + "(" + configuration + ")";
}
The declaration expression in IsRemote’s initializer captures the result of evaluating configuration.Settings into the local variable settings, so that it can be reused in the initializer for IsAsync.

We need to be a little careful about partial types. Since the “textual order” between different parts of a partial type is not defined, it does not seem reasonable to share variables from declaration expressions between different parts. Instead we should introduce a scope within each part of a type containing the field and property initializers contained in that part. This scope is then nested within the initializer scope, which itself covers all the parts.

A similar issue needs to be addressed around the argument to the base initializer. Textually it occurs before the member initializers, but it is evaluated after. To avoid confusion, the argument list needs to be in its own scope, nested inside the scope that contains the field and property initializers (of that part of the type). That way, locals introduced in the argument list will not be in scope in the initializers, and members introduced in the initializers cannot be used in the argument list (because their use would textually precede their declaration).

Primary constructors in VB

Importantly, the notion of the initialization scope would also make it possible to introduce primary constructors in VB. The main impediment to this has been that, because of case insensitivity, the restriction that primary constructor parameters could not coexist with members of the same name became too harsh. If you need both a parameter, a backing field and a property, you quickly run out of names!

The initialization scope helps with that, by introducing a separate scope that the parameters can live in, so they no longer clash with other names.

Unlike C#, VB today allows initializers to reference previously initialized fields. With the initialization scope this would still be possible, as long as there’s not a primary constructor parameter shadowing that field. And if there is, you probably want the parameter anyway. An if you don’t, you can always get at the field through Me (VB’s version of this).

It is up to the VB design team whether to actually add primary constructors this time around, but it is certainly nice to have a model that will work in both languages.

Conclusion

The initialization scope solves many problems, and leaves the language cleaner and with less magic. This clearly outweighs the slight oddities it comes with.

Part II, Part III
Apr 30, 2014 at 5:55 PM
Good call on indexed members IMO. I'm happy to see that "Assignment to getter-only auto-properties from constructors" is still on the list. OTOH the more hoops I see the team jump through to make primary constructors work the more I think that this feature isn't worth it. I mean yeah, it saves some boiler plate code but at least every C# dev understands that boiler plate code. Some of the "scope" workarounds proposed do indeed look pretty odd and have to be learned. Is it worth it to make C# that much more difficult to wrap your head around to save a little bit of boiler plate code? Wasn't it Anders that said that every language feature starts out in the red and has to show significant value just to make it into the black? I don't think primary constructors has made it into the black yet. :-(
Apr 30, 2014 at 6:20 PM
I don't think primary constructors has made it into the black yet. :-(
Indeed. Initially primary constructors looked mildly interesting but now, after seeing primary constructor bodies, I'm left wondering: what exactly is this feature trying to solve? How is writing a primary constructor with a body better than writing a normal constructor? Additionally, one of the problems that primary constructors were trying to solve has now been solved by "Assignment to getter-only auto-properties".

So, what's left that's actually valuable?
Apr 30, 2014 at 6:51 PM
I very much agree with the decision to remove indexed members. The syntax was awkward for very little benefit.

On the other hand, I very much like primary constructors. It's a lot nicer to write, for instance:
class MyClass(int x, int y, int z)
{
    public int X { get; } = x;
    public int Y { get; } = y;
    public int Z { get; } = z;
}
instead of
class MyClass
{
    public MyClass(int x, int y, int z)
    {
         X = x;
         Y = y; 
         Z = z;
    }

    public int X { get; } = x;
    public int Y { get; } = y;
    public int Z { get; } = z;
}
I haven't fully followed your reasoning on scopes yet, but: Do you really want to allow something like that?
public class ConfigurationException(Configuration configuration, string message) 
    : Exception(message)
{
    private Configuration configuration = configuration;
    public bool IsRemote { get; } = (var settings = configuration.Settings)["remote"];
    public bool IsAsync { get; } = settings["async"];
    public override string ToString() => Message + "(" + configuration + ")";
}
I'd argue that code like that won't make it through any peer review. Why don't you just disallow that? Especially since we now have bodies for primary constructors and we can assign to read-only properties. So, in my opinion, the following should be preferred in any case:
public class ConfigurationException(Configuration configuration, string message) 
    : Exception(message)
{
    private Configuration configuration = configuration;

    {
       if (configuration == null) throw ArgumentNullException(configuration);
       var settings = configuration.Settings;
       IsRemote = settings["IsRemote"];
       IsAsync = settings["async"];
    }
    public bool IsRemote { get; }
    public bool IsAsync { get; }
    public override string ToString() => Message + "(" + configuration + ")";
}
Especially when you take argument validation into account, the latter should clearly be the preferred solution. All in all, this might significantly reduce the complexity of the feature.
Apr 30, 2014 at 7:18 PM
It's a lot nicer to write, for instance:...
Yes, that's indeed nicer but that's about the only case where this is useful. Consider your last example, how is that better than using a normal constructor:
public class ConfigurationException 
{
    private Configuration configuration;

    public ConfigurationException(Configuration configuration, string message) 
       : Exception(message) 
    {
       if (configuration == null) throw ArgumentNullException(configuration);
       this.configuration = configuration;
       var settings = configuration.Settings;
       IsRemote = settings["IsRemote"];
       IsAsync = settings["async"];
    }
    public bool IsRemote { get; }
    public bool IsAsync { get; }
    public override string ToString() => Message + "(" + configuration + ")";
}
Is avoiding writing the class name twice and removing the line "this.configuration = configuration;" really worth the whole trouble with primary constructors?
Apr 30, 2014 at 8:33 PM
  1. Agree with previous posts: Initialization scope solves a problem with primary constructors, but if it makes the initialization code strewn all over the class definition instead of packaged up, that's a much too hard hit on readability. It seems that you're not going to get rid of the code in the first place, and get people into bad habits of forgetting eg argument validation by making it impossible or less than obvious for it to happen somewhere.
  2. Removal of indexed members: boo, hiss. I was looking forward to them because they could be very helpful cues to future readers as well as to the IDE that you are using a plain string, which itself is devoid of meaning, in a particular way. For example, they could be subject to refactoring. Yes, they could be a negative example, a counterweight to using C# the way it is intended. So's dynamic, and I'd like to enlist Anders' argument here: the opinion that it would usually be better if you wouldn't do it that way is not a convincing reason that that way can't be made nicer for when you do have to do it that way.
Apr 30, 2014 at 8:40 PM
I like primary constructors a lot and I want to see them in the language. It's not something you'll use everyday, but when you just need to create a type really quickly having all that boilerplate is a huge pain in the neck. I hate writing useless little DTO classes that take a few minutes to write and then are a pain to maintain because you have to separately keep constructor parameters, properties, and property initialization in sync.
Apr 30, 2014 at 9:29 PM
mdanes wrote:
Yes, that's indeed nicer but that's about the only case where this is useful. Consider your last example, how is that better than using a normal constructor:
I have to admit that I agree with you - for the ConfigurationException example, I'd also rather use a normal constructor than a primary one. However, for small immutable data types, primary constructors are a win and are indeed worth adding to the language. You could even further simplify my example above:
class MyClass(
   public readonly int X, 
   public readonly int Y, 
   public readonly int Z)
{
}
However, I agree that more complex examples are not a good fit for primary constructors. That's also why I would not like to see strange initialization code spread all over the class with class-initialization-scoped variables declared as a side effect of some field initializer. Ugly. Again, ConfigurationException as proposed by madst should be more of an anti pattern. If special rules need to be added to C# to support this scenario - don't add them. If it's just a possibility that follows from the more refined rules, I can live with that but will never ever use it.
May 1, 2014 at 9:28 PM
I think these recent additions to Primary Constructors make them very powerful, so powerful in fact that unless you have multiple constructors you'll never need to write a regular constructor.

This isn't a good thing though. I am not excited about seeing that code in a project.

Let's really sit back and think about what we're going to use Primary Constructors for, it's just going to be simple DTO objects.

Rather than solve it with a very flexible syntax that will allow lots of awful code that no-one in the world will actually want, why don't we just let people create those DTO objects very easily. I'd propose adding a record type like mentioned here but don't relying on the primary constructor interface, just compile straight to the equivalent C# 5.0 code.

For example:
class Point(int X, int Y);
would become:
class Point
{
   public int X {get;}
   public int Y {get;}
   public Point(int x, int y)
   {
      this.X = x;
      this.Y = y;
   }
   //also define Equals and GetHashCode
}
This would be the cleanest and simplest syntax possible for those extremely common DTO objects, it'd promote immutability (which is a good thing), and it wouldn't require adding Primary Constructors (the only new syntax required is ability to assign to readonly auto-properties in constructors)

Primary Constructors are just way too complex to use in complicated cases, and for simple cases this record syntax would be much cleaner than what is proposed.
May 1, 2014 at 11:06 PM
Edited May 1, 2014 at 11:08 PM
I definitely like the class Point(int X, int Y); syntax a lot for declaring quick DTOs. I'd go so far as to say you should even be able to do this from within the body of a method. You can create anonymous types on the fly which implement GetHashCode() and Equals(), why not be able to create named types quickly that are equally as powerful? I would propose that in addition to GetHashCode() and Equals() that they also override ToString() and provide an implementation which prints out all the properties.

I disagree though that this nice shorthand idea means that primary constructors then become useless. If you want to do anything besides make a DTO, you have to default back to the existing (C# 5.0) overly verbose syntax.

I would say that the constructor body syntax as proposed is definitely a little wonky though. I think the fact that the brackets are not typographically connected to anything can make the code very misleading to read. When I read this example:
partial class C(int x1) : B(int x3 = x1 /* x2 in scope but can’t be used */)
{
    public int X0 { get; } = (int x2 = x1);
    {
        int x4 = X0 + x1 + x2 + x3;
    }
}
I had to read it a couple times before getting my brain to register that the inner brackets were not related to the property declared directly above it. I think this could be improved a lot by adding some keyword to denote a constructor body. Personally, I'd take a page from TypeScript/ES6 and use constructor. So the example given would become:
partial class C(int x1) : B(int x3 = x1 /* x2 in scope but can’t be used */)
{
    public int X0 { get; } = (int x2 = x1);
    constructor 
    {
        int x4 = X0 + x1 + x2 + x3;
    }
}
This, in my opinion, is much, much clearer.

Of course, if you went down this rabbit hole the natural next question is why not allow constructor to denote the declaration of any constructor, not just primary constructor bodies. I think that that too, is a great idea as it keeps the code far more DRY (don't repeat yourself), which the current constructor design suffers from, and makes refactoring easier. (Admit it, there are plenty of times when you forget to use F2 and just tweak a name and then the code breaks because the type name and constructor name are not in sync anymore). I know some people are opposed to redundant syntax, but it would not be a first for the language; see array initialization, LINQ, and anonymous delegates/lambdas.

Also, it wasn't clear to me from the meeting notes why constructor bodies were preferable over initializer bodies. It seems like initializer bodies are the more useful as you can perform validation on the primary constructor parameters before they get assigned to properties. Wasn't that the entire point of adding this feature, to perform validation on primary constructor parameters?

Finally, I'm sad that the Indexed member access has been withdrawn. Though not really useful yet, my impression was that the C# team had plans to implement Intellisense and autocompletion support for these to better support "lightweight dynamic" scenarios. String based indexers make it difficult to give you autocompletion, and they cannot give you intellisense when you hover over them. I feel like the preview needed to include the intellisense/autocomplete features along with the indexed member access syntax for the community to give the feature a fair shot before judging it.
May 1, 2014 at 11:15 PM
JesperTreetop wrote:
  1. Agree with previous posts: Initialization scope solves a problem with primary constructors, but if it makes the initialization code strewn all over the class definition instead of packaged up, that's a much too hard hit on readability.
I would argue that the present design requires an unpleasant separation between the declaration of write-once variables and their usage. Further, while C# allows field values to be set before calling the base constructor, and does this for the purpose of making those values available to virtual functions called from the base constructor, the feature is not at present usable in cases where initialization would depend upon information passed to the class constructor.

Personally, I would like to see both VB.NET and C# allow field declarations to specify either "early" or "late" initialization, since there are usage cases for allowing write-once fields to be initialized using the values of other fields, and with the exposure of constructor parameters to fields there will be usage cases for allowing field initializations to precede the base constructor call. Rather than arguing about which is better, it would be more helpful for each languages to simply allow each approach to be used when appropriate. This would also help facilitate code migration between C# and VB.NET.
May 1, 2014 at 11:43 PM
Just to be clear, the initialization scope is there for just one purpose: to nest the separate the declaration space of the primary constructors from (and nest it within) the declaration space for type members.

This cleanly enables primary constructor parameters to have the same name as type members (typically private fields):
public class Person(string first, string last, DateTime birthdate)
{
    private DateTime birthdate = birthdate;

    public string First { get; } = first;
    public string Last { get; } = last;

    public int Age
    {
        get
        {
            var now = DateTime.Now;
            var hadBirthdayThisYear = birthdate.DayOfYear < now.DayOfYear;
            return (now.Year - birthdate.Year) - (hadBirthdayThisYear ? 0 : 1);
        }
    }
}

Without the initialization scope you wouldn't be able to declare both the parameter and the field birthdate.

The approach happens to also enable some other things, that I've explored at length in the notes. It gets complicated; we have to consider every corner. But that shouldn't distract from the core value of the initialization scope; those more complicated aspects (scopes within scopes within ... ) are just mechanism; they don't get in your face. In fact they are the language's way of providing "natural" or "expected" behavior.
May 2, 2014 at 1:09 AM
madst wrote:
This cleanly enables primary constructor parameters to have the same name as type members (typically private fields):
You say that like it is a good thing. ;-) Seriously though, this bit:
private DateTime birthdate = birthdate;
Is confusing looking to me (like it should be illegal). In other places such as method parameters and field names, you get a warning "Assignment made to same variable; did you mean to assign something else". You can eliminate the warning by using "this." or prefixing your fields with "_" but that is changing one of the two names. BTW I assume the example above wouldn't generate a similar warning. :-)

In your example, you assign birthdate straight across so I didn't have to guess which "one" was in scope in any particular spot in the code. How about this example?
public class LogEntry(string hostname, string header, DateTime timestamp)
{
    private DateTime timestamp = timestamp.ToUniversalTime();

    public string HostName{ get; } = hostname;
    public string Header { get; } = header;
    public DateTime Foo { get; } = timestamp; // Which timestamp - field or ctor param

    public TimeSpan Age
    {
        get { return ( DateTime.UtcNow - timestamp); }  // Which timestamp - field or ctor param
    }
}
I could see folks getting a bit confused in Foo and Age as to which "timestamp" they are getting. I think Foo gets the ctor parameter and Age gets the field, right?
May 2, 2014 at 1:14 AM
@r_keith_hill: It is always confusing when you use the same name to designate different things! That would be bad even if you used existing constructor syntax! I agree that there's an extra layer to the confusion when the names can be interleaved a little more in code. But I don't think making really bad code a little worse disqualifies a feature! :-)
May 2, 2014 at 7:53 AM
Edited May 2, 2014 at 8:13 AM
In my opinion, primary constructors are the most useful when they're used to initialize and declare fields:
class MainControl
{
    private readonly IVehicleDetector leftDetector;
    private readonly IVehicleDetector positionDetector;
    private readonly IVehicleDetector rightDetector;

    public MainControl(
        IVehicleDetector positionDetector,
        IVehicleDetector leftDetector,
        IVehicleDetector rightDetector)
    {
        this.positionDetector = positionDetector;
        this.leftDetector = leftDetector;
        this.rightDetector = rightDetector;
    }
    // ...
}
simply becomes:
class MainControl(
        private readonly IVehicleDetector positionDetector,
        private readonly IVehicleDetector leftDetector,
        private readonly IVehicleDetector rightDetector)
{
    // ...
}
That is indeed a big advantage and saves a lot of repitition (write the type of the fields only once instead of twice, write the name of the fields only once instead of four times!) . So it's not so much about not having to retype the name of the class again when writing the constructor. And, MgSam, I'm sorry but forgetting to press F2 when renaming types is not something that must be fixed at the language level, it must be fixed in your head. Plus not doing a renaming refactoring not only breaks your constructors, but all your other code using your class as well. There's nothing the language can do there, unless we'd have extremely sophisticated type inference similar to F#.

@mirhagk: I'd also like to see something similar to F#'s record types. We're almost have-way there with primary constructors. Now we only need a with keyword to make copies of immutable types and pattern matching. The latter of which is apparently already planned for VB 7 or so, so let's hope it'll come to C# 7 too.

MgSam wrote:
Finally, I'm sad that the Indexed member access has been withdrawn. Though not really useful yet, my impression was that the C# team had plans to implement Intellisense and autocompletion support for these to better support "lightweight dynamic" scenarios.
I also seem to remember that someone from the C# team (was it madst?) mentioned a couple of interesting features planned for indexed members somewhere. But as you said yourself, they're "not really useful yet" - so don't add them as long as they're not useful. Especially since later uses the C# team might come up with might have required a different specification of the feature. Add indexed members when they're ready and clearly provide a benefit. Before that, it's probably not a good idea.

MgSam wrote:
partial class C(int x1) : B(int x3 = x1 /* x2 in scope but can’t be used */)
{
    public int X0 { get; } = (int x2 = x1);
    {
        int x4 = X0 + x1 + x2 + x3;
    }
}
I had to read it a couple times before getting my brain to register that the inner brackets were not related to the property declared directly above it. I think this could be improved a lot by adding some keyword to denote a constructor body. ...
Yes, I got it wrong the first time, too. But that's probably only a code formatting issue. There should have been an empty line in between, or you probably should always define the body of a primary constructor first, or following all field declarations, etc. On the other hand, adding a keyword like you suggested might help, though I'd prefer primary instead of constructor since the body you're defining is the primary constructor's body. As mentioned above, I don't think a constructor syntax as a replacement of or alternative to the normal constructor syntax is required or desirable.
May 2, 2014 at 1:45 PM
If this
class MainControl(
        private readonly IVehicleDetector positionDetector,
        private readonly IVehicleDetector leftDetector,
        private readonly IVehicleDetector rightDetector)
{
    // ...
}
is the desired conditions for Primary Constructors, then the language should allow this, and shouldn't go much further. I don't think introducing primary constructor bodies and initialization scope is the way to go. They are VERY ugly features, and the only purpose they serve is to bring Primary Constructors to the same level of power as regular constructors, which isn't something we need.

Support the above syntax, and then end it there. If you want something more, than write regular constructors, it's note really much more bloat, and it's certainly clearer what's going on. Most of the other features brought in make this concept very confusing, and will bring way more trouble than it's worth.

If you limit Primary Constructors to just the above syntax, and that's it (automatically creating fields based on the types), then these have a chance to be used in teams, people understand what's happening. If you introduce initialization scope and constructor bodies, then Primary Constructors get a whole lot more confusing, and many companies will ban their use completely. The introduction of the more complicated case makes it so that the simple case isn't allowed to be used.

As an example of what I mean, look at the implementation of goto. It's very limited, and because of that it's sensible to allow the usage of it (especially with switch case statements). If you could goto anywhere like C, then the use of it would likely be banned from every team.
May 2, 2014 at 2:09 PM
Expandable wrote:
And, MgSam, I'm sorry but forgetting to press F2 when renaming types is not something that must be fixed at the language level, it must be fixed in your head.
You're taking that bit of my post out of context. My suggestion for a constructor keyword was for primary constructor bodies, and keeping the code more DRY for all constructors might be a nice side effect.

It would have other benefits besides my silly renaming example as well. When I'm writing TypeScript and reviewing a code file, it is much more clear when scanning over the code to identify the constructor because it's actually labeled constructor. In C#, the type name might be the class declaration, a constructor, a static call to the class, a construction of an instance of that class, or a type parameter.

It would be definite improvement, in my opinion, if constructors were simply labeled as constructors. I think code should say what it means and be self explanatory. Every time I retype the type name for a constructor I can't help think that this is some arcane incantation I'm forced to repeat solely because it's how Java/C++ did it.
though I'd prefer primary instead of constructor since the body you're defining is the primary constructor's body
But then rather than address a more general case you're only addressing the narrow case. Under your proposal constructor bodies declared via primary constructor syntax look fundamentally different than any other constructor when the language design team is going out of their way to ensure they have the same semantics. That seems like a higher learning curve to me.
May 2, 2014 at 4:33 PM
Edited May 2, 2014 at 4:56 PM
mirhagk wrote:
If this is the desired conditions for Primary Constructors, then the language should allow this, and shouldn't go much further. I don't think introducing primary constructor bodies and initialization scope is the way to go. [...] Support the above syntax, and then end it there. [...] If you limit Primary Constructors to just the above syntax, and that's it (automatically creating fields based on the types), then these have a chance to be used in teams, people understand what's happening.
I've been thinking about that as well. Especially since we can now write to readonly properties in the constructor, do we really still need the syntax that has been proposed by the C# team? How about a primary keyword, allowing for the following code:
class MainControl
{
    public primary MainControl(
        private readonly IVehicleDetector positionDetector,
        private readonly IVehicleDetector leftDetector,
        private readonly IVehicleDetector rightDetector)
    {
    }

    // Other non-primary constructors...
    MainControl() {}
    // ...
}
There can of course only be one primary constructor and only primary constructors allow the declaration of "field parameters". That would not require any complex new rules for declaration scopes, disallow the use of variables throughout the initialization of fields, solve the problem r_keith_hill mentioned above, not clutter up the actual declaration of the type with constructor parameters, and basically the only syntax change would be to allow modifiers on constructor parameters. That syntax would look a lot more like the C# we're all used to. The difference between primary and non-primary constructors would be minimal, but there would still be a significant advantage when defining types like MainControl above or my MyClass example a couple of posts ago:
class MyClass
{ 
   public primary MyClass(
      public readonly int X, 
      public readonly int Y, 
      public readonly int Z)
   {
   }
}
@madst: Has something like this been considered by the C# design team? If there aren't any significant downsides that I overlooked, I'd definitely urge you to consider this alternative.

Edit: You might say that now the "field parameters" are defined in a scope nested within the class declaration scope; at a "lower level" so to say. The current syntax defines them at a higher scope. But basically, in each case the fields get generated in a different scope, so "higher" or "lower" shouldn't really matter as there always is a scope change. So that's somewhat uncommon in C#, but the addition of static usings is basically doing the same thing.

Edit 2: This would also solve the "Separate accessibility for type and primary constructor" issue mentioned in the language design notes. Trivially possible.
May 2, 2014 at 4:38 PM
madst wrote:
Without the initialization scope you wouldn't be able to declare both the parameter and the field birthdate.
How about, within initialization contexts, having params act syntactically like a read-only struct whose fields are the parameters? Thus:
private DateTime birthday = params.birthday;
Problem solved.

It would also be helpful to be able to have a means of making each field declaration be either "early-init" [the default, with values available to the base constructor], "late-init" [for parity with VB.NET, able to use values set by the base constructor], or "temporary"; a temporary "field" declaration wouldn't actually declare a field, but would instead behave as a variable which would only last through initialization. One could thus do something like:
class myThing<T>(int size)
{
    temp private int arraySize = params.size > 15 ? params.size : 15;
    T[] data = new T[arraySize];
    int[] links= new int[arraySize];
}
Incidentally, if C# is supposed to expose the power of the CLR, it would also be helpful to have a syntax where constructors could do things before calling the base. Indeed, such an ability, combined with the ability to write fields or read already-written fields, would probably allow for anything just about anything primary constructors can do. For example:
class myThing<T>
{
  T[] data, int[] links;

  myThing(int initialSize)
  {
    initialSize = initialSize > 15 ? initialSize : 15;
    data = new T[initialSize];
    links = new int[initialSize];
    base();
    // Main constructor body goes here
  }
Syntactically, if a variable is only going to be set once, I think it's cleaner to have it be done at the declaration point than a constructor which is separate from the declaration, but semantically, the main ability which is presently lacking is the ability to establish parameter-dependent subclass invariants before invoking the base constructor, and in the general case that would be most flexibly handled by allowing constructors to take care of that themselves.
May 2, 2014 at 4:44 PM
supercat wrote:
class myThing<T>(int size)
{
    temp private int arraySize = params.size > 15 ? params.size : 15;
    T[] data = new T[arraySize];
    int[] links= new int[arraySize];
}
The more I see examples like that, the more I hate the idea of having code directly nested within a type, outside of any method. Please don't do that. Please don't support that.
May 2, 2014 at 4:51 PM
I think the main thing to take away is that very few people are happy with the current implementation. There is way too much discussion about this, and at this rate we won't find a result people are happy with for years.

I'd suggest taking primary constructors out of C# 6.0, leave it for C# 7.0. Have assigning to get only auto properties, and give us the record types class Point(int X, int Y); and we solve 99% of the need for primary constructors.

Then we can see if it's needed, but I don't want to see C#6.0 be slowed down by this discussion.
May 2, 2014 at 5:18 PM
I think the main thing to take away is that very few people are happy with the current implementation. There is way too much discussion about this, and at this rate we won't find a result people are happy with for years.
@mirhagk I think trying to draw conclusions about the entire population of C# developers from the tiny subset represented on these forums is foolhardy. Anyone who posts on forums about something is likely to have a negative bias- you're much more likely to post if you have something to complain about. Any non-trivial feature is going to have a large number of detractors- I'm sure if the team did a poll before C# 5.0 about what features people wanted async and await would have come no where close to the top, and there would have been lots of people saying it adds too much complexity to the language. Yet in retrospect it's addition is practically revolutionary- fundamentally improving the performance of a lot of code with minimal effort and influencing other languages to consider adding similar features.

I think the discussions are beneficial in that it gives the team more to think about and offers the perspectives of some people passionate about the language. But at the same time, they need to be taken for what they are- musings, often emotional, by non-experts in language design. For instance, there's been quite a bit of hand wringing about poor coding patterns because of some of the corner case examples Mads illustrated in the design notes. You can write equally horrific looking code with existing features if you wanted to, but as Mads said, this is not a reason to disqualify a feature.
May 2, 2014 at 5:29 PM
Expandable wrote:
The more I see examples like that, the more I hate the idea of having code directly nested within a type, outside of any method. Please don't do that. Please don't support that.
If initialization needs to occur before the base constructor executes, and if initialization depends upon constructor parameters, what syntax would you prefer? The creators of C# decided it was worthwhile to have objects configure themselves with field initializers before running the base constructor, but at present the only way to have such initializers depend upon constructor parameters is a really nasty hack using threadstatic variables.

Further, I would suggest that a combined declaration/initialization like
public readonly int NumRows = params.numRows;
public readonly int NumColumns = params.numColumns;
protected readonly double[,] data = new double[numRows,numColumns];
makes it clear that data will hold an array of the aforementioned dimensions. By contrast, seeing
public readonly int NumRows, NumColumms;
protected readonly double[,] data;

public className(int numRows, int numColumns)
{
   this.NumRows = numRows; // use 'this.' to increase "Hamming distance" between right and wrong code...
   this.NumColumns = numColumns; // ... versus relying upon case alone.
   data = new double[numRows,numColumns];
}
would not establish the invariant unless that was the only constructor. If there were some other constructor (perhaps intended for use by e.g. a derived SparseMatrix class which used a different backing store)
protected className(int numRows, int numColumns, bool dontCreate)
{
   this.NumRows = numRows;
   this.NumColumns = numColumns;
   if (!dontCreate)
     data = new double[numRows,numColumns];
}
the "invariant" might not get established. Only by looking through all constructors could one determine whether the apparent "invariant" actually was.
May 2, 2014 at 6:06 PM
Expandable wrote:
public primary MainControl...
Looks a bit like a method which returns a primary.

How about
partial new partialName(int foo, int bar)
{
}
with the ability to declare fields within a paritial-initializer, and have a constructor call partial initializers before chaining to base, or have partial initializers call other partial initializers, but with a requirement that that every possible normally-returning execution paths through every constructor must statically recognizable as producing the same sequence of partial-initailizer and base-initializer invocations, with each partial initializer being invoked exactly once (such invocation would be forbidden within loops, but would be allowed in if/then or switch statements provided that every branch called the same initializers in the same sequence.

If the compiler were to process such initializers by macro-expanding them while generating code for constructors, the compiler could allow initializers to make use of fields which had been initialized before they were run, but forbid them from making use of fields that were not yet initialized. Although problems in a partial initializer may not become apparent until a constructor is compiled, a breadth-first verification that every constructor or partial initializer always performed the same sequence of invocations before compiling constructors would make it pretty clear at what level errors should be reported.

The more I think about this design, the more I like it. It would solves the problems of DRY, it would clean up ambiguities as to when initializers run, it would combine all the advantages of early and late initialization, etc. especially if auto-property declarations allowed e.g. {get; private var;}and{get; private readonly var;} which would indicate code within the class should the property name as an alias to its backing field, while outside code should see a property (such declarations would make it possible for partial-initialization blocks to values of earlier-set properties).
May 7, 2014 at 11:16 PM
Edited May 7, 2014 at 11:28 PM
hi all,
to disambiguate the name clash: why not simply use the same trick we're all used to since the beginning of time ?
i'm talking about something like:
public class LogEntry(string hostname, string header, DateTime timestamp)
{
    private DateTime timestamp = timestamp.ToUniversalTime();
    public string HostName{ get; } = hostname;
    public string Header { get; } = header;

    // when there's no "this.", we mean the constructor parameter
    public DateTime Foo { get; } = timestamp; 

    public TimeSpan Age
    {
        // when there's "this." we mean the field
        get { return (DateTime.UtcNow - this.timestamp); }  
    }
}
one downside of this approach would be that you if you create your class first without the primary constructor then you later add one with a name clash you may change the meaning of the variable everywhere in your code silently in an instant (which is not following the "pit of success" principle of C#). so while the above syntax would work i think that any primary constructor parameter name clash should show up as a warning anyway.
May 8, 2014 at 12:37 AM
mirhagk wrote:
I think the main thing to take away is that very few people are happy with the current implementation. There is way too much discussion about this, and at this rate we won't find a result people are happy with for years.

Then we can see if it's needed, but I don't want to see C#6.0 be slowed down by this discussion.
The design and engineering teams keep moving regardless of what goes on in this forum. Don't mistake open development for uncoordinated development.
May 8, 2014 at 1:07 AM
ram_longcat wrote:
    // when there's no "this.", we mean the constructor parameter
How about having a pseudo-field params which syntactically behaves as a read-only structure containing the constructor parameters?
May 9, 2014 at 10:13 AM
We are trying to avoid the field variables by using implicit properties since long time. Now the same can be achieved without avoiding to duplicate the parameter declaration and assignment though. By introducing an attribute (similar to caller information in 5.0).

To me, if this is merely to simplify the usage and avoid duplicate class name as someone already mentioned in this thread, then it can be done without lot of change.

Like (I am trying to use the same example what 'Expandable' has used)
class MyClass(int x, int y, int z)
{
    public int X { get; } = x;
    public int Y { get; } = y;
    public int Z { get; } = z;
}
can be just
class MyClass
{
    [constructor] public int X { get; }
    [constructor] public int Y { get; }
    [constructor] public int Z { get; }
}
where "new MyClass (10, 20, 30)" will get automatically assigned to X, Y, Z.

My points of not liking this are
  1. I somehow do not like the parameters on the classname which would lead to confusion during code reviews.
  2. I see no value in adding the constructor parameters with the classname unless we are forcing the user to create an instance with those parameters.
  3. not sure how constructor overloading can be done
  4. Introducing a attribute to do the job is a change in the meta programming which does not affect the syntax tree much (as far as I think.. I may be wrong).
May 9, 2014 at 4:31 PM
Edited May 9, 2014 at 4:34 PM
rvwaran wrote:
  1. not sure how constructor overloading can be done
I would suggest that including parameters with a class name should auto-define a public constructor with those parameters if no other constructor is defined. Otherwise have constructors use syntax like:
class foo(int length) : bar
{
  private readonly arr = new int[params.length]; // Allow type inference with auto-initialized read-only fields

  foo(int x) : this(x), base() // Constructor #1 (sets parameters and chains to base)
  {
  }
  foo(int x, int y) : this(x) // Constructor #2 (just chains to #1)
  {
  }
  foo(int x, int y, int z) : this(x), base(y,z); // Constructor #3 (sets parameters and chains to another base)
  {
  }
}
Any constructor which doesn't chain to another of the same type, and only those constructors, should use a this(params) before the chained call to set the class parameter values. Public, private, protected, internal, etc. declarations within class parameters should define fields or auto-properties, depending upon the presence of {get;} etc.; in the absence of such markings, they should simply define temporary variables.

The one sllight ambiguity would be with case #2 above; it might be plausibly have been intended to initialize parameters and then chain to base, but since the ability to initialize parameters is new, I don't think it unreasonable to say that such ability is only used when a constructor is specified as chaining to something else--even the default base().

For auto-properties which should be publicly readable, but which a class will need to manipulate internally, I would suggest using the syntax {get; private var;} and {get; private readonly var;}. When a property is declared in such fashion, the name should refer to the backing field when used within the type, or to the property when used outside the type (much the way auto-event names do). Beyond avoiding the semantic quirkiness of readonly set, that would also allow things like [ignoring for now the ability to use parameters for inline initialization]
struct ImmutablePair<T1,T2>
{
  public T1 First {get; private readonly var;}
  public T2 Second {get; private readonly var;}

  ImmutablePair(T1 first, T2 second)
  {
    First = first;
    Second = second;
  }
}
Under present rules, if First had been declared {get; private set;} it would be necessary to zero out the structure before accessing any property thereof. Using readonly var; would eliminate such a requirement, since First = first; would be a field write, rather than a property invocation.
May 12, 2014 at 1:15 AM
Primary constructors with primary constructor bodies? Didn't we use to call them constructors? The only benefit I've ever seen with primary constructors is to avoid the need to declare a ctor body and fields when all you're going to do is assign the ctor parameters to the fields. If you need anything beyond that then why would wouldn't you just create a normal ctor? It seems like all this talk about field initializer expressions, primary ctors and bodies and initialization scope is really just trying to solve design issues around primary ctors being anything more than simple assignments. Why not just say primary ctors are equivalent to simple ctor assignment and call it a day? If a dev needs anything beyond that then they should fall back to standard ctors. I fail to see any benefit in creating new stuff that people have to know when a basic ctor already handles it. Do we have no more interesting problems to solve beyond how to save one ctor body?
May 13, 2014 at 2:31 AM
CoolDadTx wrote:
If a dev needs anything beyond that then they should fall back to standard ctors.
Present constructors have at least two deficiencies:
  1. At present, the only fields which C# can initialize before chaining to the base ctor are those whose value does not depend in any way upon the value of any constructor parameters nor upon the values assigned to other fields.
  2. At present, unless a readonly is initialized with a value which doesn't depend upon constructor parameters or other fields, there's no way for code to set the field's value and affirm that it is the only way it will be set. Only if one can inspect all constructors that will ever be written can one ensure that all constructors will abide by a class's invariants.
I would posit that if these deficiencies can be fixed without excessive effort, they should be.
May 16, 2014 at 9:32 PM
Well, indexed members was a nice idea. What about a syntax like

dict."item"

It makes it obvious that it is a string, and a part of a dict, and solves a problem of multiword strings.

In the case of dictionaries with string keys it could really help, and the use case is pretty wide spread.
May 17, 2014 at 12:42 AM
kaerber wrote:
Well, indexed members was a nice idea. What about a syntax like

dict."item"
Why not dict["item"]?
May 17, 2014 at 8:04 PM
supercat wrote:
CoolDadTx wrote:
If a dev needs anything beyond that then they should fall back to standard ctors.
Present constructors have at least two deficiencies:
  1. At present, the only fields which C# can initialize before chaining to the base ctor are those whose value does not depend in any way upon the value of any constructor parameters nor upon the values assigned to other fields.
What would be the use case for allowing this? Sounds like you'd want the derived class to be able to assign values to protected fields that the base constructor would then use. Why would that be better than passing that parameter to the base class constructor?
  1. At present, unless a readonly is initialized with a value which doesn't depend upon constructor parameters or other fields, there's no way for code to set the field's value and affirm that it is the only way it will be set. Only if one can inspect all constructors that will ever be written can one ensure that all constructors will abide by a class's invariants.
From the design notes it sounds like the C# team was opening up readonly auto-properties so that any constructor could write to them which would be interpreted as writing directly to the backing field, which would be marked as readonly. Does that nof satisfy your request?
public class Foo
{
    public int Bar { get; }

    public Foo(int bar)
    {
        Bar = bar;
    }
}
May 18, 2014 at 4:29 AM
Halo_Four wrote:
supercat wrote:
  1. At present, the only fields which C# can initialize before chaining to the base ctor are those whose value does not depend in any way upon the value of any constructor parameters nor upon the values assigned to other fields.
What would be the use case for allowing this? Sounds like you'd want the derived class to be able to assign values to protected fields that the base constructor would then use. Why would that be better than passing that parameter to the base class constructor?
Base-class fields can't be accessed before the base constructor in any case; the issue is with base classes that may invoke virtual methods before the derived class is built. The creators of C# decided to have field initializers run before the base constructor to allow for this, but unfortunately their abilities are so limited that virtual methods may as well simply use a "dejavu" flag.
  1. At present, unless a readonly is initialized with a value which doesn't depend upon constructor parameters or other fields, there's no way for code to set the field's value and affirm that it is the only way it will be set. Only if one can inspect all constructors that will ever be written can one ensure that all constructors will abide by a class's invariants.
From the design notes it sounds like the C# team was opening up readonly auto-properties so that any constructor could write to them which would be interpreted as writing directly to the backing field, which would be marked as readonly. Does that nof satisfy your request?
The desire is to specify that a variable will be written exactly once, and will never be observed to have any value other than the one that was written at that time. Additionally, I think that having write-once variables set at the point of declaration is cleaner that having to set them in imperative code, particularly imperative code which isn't guaranteed to be the only thing that writes to the variable.
public class Foo
{
public int Bar { get; }

public Foo(int bar)
{
    Bar = bar;
}
}
Unless you examine the entire code for the class, there's no guarantee that the aforementioned write is the only one to bar.
May 18, 2014 at 1:09 PM
supercat wrote:
Base-class fields can't be accessed before the base constructor in any case; the issue is with base classes that may invoke virtual methods before the derived class is built. The creators of C# decided to have field initializers run before the base constructor to allow for this, but unfortunately their abilities are so limited that virtual methods may as well simply use a "dejavu" flag.
A mistake to compensate for a mistake (C# should've never permitted virtual calls from a constructor, it should've taken that page from C++ and forced those calls to the methods on the base class only). Given that this is a known antipattern why encourage it's further use by expanding the functionality? And that doesn't explain actual use cases, that just describes the side effects of how poorly-written code would work today.
Unless you examine the entire code for the class, there's no guarantee that the aforementioned write is the only one to bar.
I don't see what the problem is with that at all, particularly since the writing is limited to constructors. Yeah, you can have more than one constructor, and one constructor could've chained to another and both written to that field, but so what? The use cases for allowing that are already known and it fits within the OOP/imperative model of the language.
May 18, 2014 at 5:30 PM
Halo_Four wrote:
A mistake to compensate for a mistake (C# should've never permitted virtual calls from a constructor, it should've taken that page from C++ and forced those calls to the methods on the base class only).
It is frequently necessary for a constructor, as part of its duties, to expose an object to outside code. As soon as an object is exposed to the outside world, it is essentially impossible to prevent the invocation of virtual methods.

Proper object construction in many cases should be a two-phase or three-phase process (depending upon the class): Local-Prep, Class-Prep (optional), and World-Prep. During Local-Prep, all aspects of an object prepare themselves for interaction with each other and possibly the outside world, but none of them interact with each other. During Class-Prep, if applicable, the aspects of a class interact with each other as necessary to prepare for interaction with the outside world. During World-Prep, the object makes itself available to the outside world in whatever fashion is required; the object should be prepared, before the start of World-Prep, for any calls it may receive from the outside world as a result of such exposure.

It would have helpful if .NET had defined a virtual method ConstructorFinished(Exception ExceptionIfAny), possessed by all types, which would be invoked when control left the most derived constructor. If such a method existed, it would have allowed the constructor to focus entirely on Local-Prep, and let the ConstructorFinished method to take care of Class-Prep and World-Prep. If such a method existed, then it would be possible to use constructors to prepare all properties of an object so that the ConstructorFinished call could bring it to life. There would have been no need to have constructors expose the object under construction to the outside world or run virtual methods upon them, since those actions could be deferred until ConstructorFinished.

It might be possible for .NET 5.0 to implement such a feature, if classes which use ConstructorFinished are marked as requiring .NET 5.0; I wouldn't expect compatibility problems, but I'm not positive that adding a new member to Object wouldn't cause any.

In any case, because no such feature exists, there is not only no mechanism by which .NET could prevent objects from receiving virtual calls before derived constructors have run without severely limiting the ability of constructors to do much of anything useful (if a constructor exposes the object under construction to outside code, there's no way of knowing what virtual methods that outside code might call). The cleanest way for a language to allow proper multi-stage construction would be for it to let a derived class do its local-prep code before chaning to base, let any necessary class-prep actions be taken care of by virtual calls received from the base, and any world-prep actions which haven't been taken care of through such virtual methods be taken care of after the base constructor returns.
I don't see what the problem is with that at all, particularly since the writing is limited to constructors. Yeah, you can have more than one constructor, and one constructor could've chained to another and both written to that field, but so what? The use cases for allowing that are already known and it fits within the OOP/imperative model of the language.
The fact that there is occasionally a use case for writing a variable multiple times during a constructor, with reads interspersed among writes, but not after the constructor completes, doesn't imply that there isn't considerable value in allowing the compiler to enforce a declarative promise code makes to the reader indicating that it won't do such a thing.

A reader who saw declarations like:
public int Height {get; private readonly var;} = params.height;
public int Width {get; private readonly var;} = params.width;
protected double[,] data = new double[Height, Width]; // Compiler knows that those fields have been written
could know, on the basis of those declarations alone, that no matter what else might appear in the class, data would always refer to one particular array of double with dimensions Height and Width.

By contrast, given
partial public class ViewableMatrixOf Double
{
  inherits EnhancedControl;

  public int Height {get;}
  public int Width {get;}
  protected double[,] data;

  ViewableMatrixOfDouble(int height, int width}
  {      
    Height = height;
    Width = width;
    data = new double[height, width];
    InitializeComponent();
    ...
  }
}
There would be no way a programmer could be 100% positive, other than by examining every single C# file in the entire project, whether the intended invariant would actually hold. A programmer seeing the above might certainly expect that it "probably" holds, but to my mind that's not the same thing as knowing that a compiler would forbid any code from violating it.

Incidentally, while I understand the reasons for disallowing var declarations with fields, I would favor allowing the use of such declarations in the specific cases where the right-hand side is a new expression, the result of a typecast, or the result of a static factory method whose return type is the same as that of the static factory. I'm a firm believer in DRY, and being able to say:
protected readonly var customers = new System.Collections.ObjectModel.ReadOnlyCollection<CustomerRecord>(params.customers);
would seem much cleaner than
protected readonly System.Collections.ObjectModel.ReadOnlyCollection<CustomerRecord>customers = 
  new System.Collections.ObjectModel.ReadOnlyCollection<CustomerRecord>(params.customers);
or
protected readonly System.Collections.ObjectModel.ReadOnlyCollection<CustomerRecord>customers;

theType(...) // Constructor
{
  .. 
  this.customers = new System.Collections.ObjectModel.ReadOnlyCollection<CustomerRecord>(customers);
}
I appreciate that it's important to avoid the possibility of defining an exposed interface with a type other than intended, but in the three scenarios I described, I think it should be sufficiently clear what type the programmer intended the variable to be, that there would be no reason for a compiler to believe the programmer might have intended something else.
May 18, 2014 at 7:36 PM
Edited May 18, 2014 at 7:39 PM
madst wrote:
So in this code:
public class ConfigurationException(Configuration configuration, string message) 
    : Exception(message)
{
    private Configuration configuration = configuration;
    public override string ToString() => message + "(" + configuration + ")";
}
The declaration of the field configuration is currently an error, because it clashes with the parameter of the same name in the same declaration space, but it would be nice if it just worked.

The use of message in a method body is and should be an error, but it would be preferable if that was a more natural consequence of existing scoping rules, instead of new specific restrictions.


So the configuration field should be admissible, but the ToString() override should not? I'm not sure this is obviously true. The trouble is that the ToString() override looks very much like a lambda expression, which would have access to message and configuration due to closure semantics. Consider this example:
public class ConfigurationException(Configuration configuration, string message) 
    : Exception(message)
{
    private Configuration configuration = configuration;
    public Func<string> AsString = () => message + "(" + configuration + ")";
    public override string ToString() => message + "(" + configuration + ")";
}
Given the closeness in syntax between a method expression (as in ToString()) and a lambda expression (as in AsString()), it's natural to expect similar behavior. Indeed, I actually imagine the method expression syntax to be not a shorthand for existing method bodies, but as a way to use lambda expressions as method bodies directly.
May 18, 2014 at 7:40 PM
Edited May 18, 2014 at 7:42 PM
Not sure why, but after editing all my '+' chars became '&#43;' entities and it seems I am unable to restore them...

EDIT: never mind, after posting this they started appearing normally. Now the problem is that there's no way to delete this moot reply :-\
May 19, 2014 at 1:09 AM
gzak wrote:
Given the closeness in syntax between a method expression (as in ToString()) and a lambda expression (as in AsString()), it's natural to expect similar behavior. Indeed, I actually imagine the method expression syntax to be not a shorthand for existing method bodies, but as a way to use lambda expressions as method bodies directly.
What would you think of saying that if a parameter and field have the same name, then expressions using that name outside a method body must qualify it as either params.name or this.name? I've mentioned that idea a few times, but not really gotten any response.
May 20, 2014 at 12:45 AM
Edited May 20, 2014 at 12:46 AM
madst wrote:
Without the initialization scope you wouldn't be able to declare both the parameter and the field birthdate.

The approach happens to also enable some other things, that I've explored at length in the notes. It gets complicated; we have to consider every corner. But that shouldn't distract from the core value of the initialization scope; those more complicated aspects (scopes within scopes within ... ) are just mechanism; they don't get in your face. In fact they are the language's way of providing "natural" or "expected" behavior.
But see, when I see a piece of code like this:
public void Abcde(string text)
{
    ....
The natural, expected behaviour of many programming languages is that x, y, z are available both within the current scope as well as its child scopes. Example:
public Func<string> Flip(string text)
{
    return () => text.Reverse().Aggregate("", (s, c) => s + c);
}
If you were to present me with a declaration like this:
public class StringWrangler(string text)
{
    ....
i would expect identical semantics:
    public Func<string> Flip()
    {
        return () => text.Reverse().Aggregate("", (s, c) => s + c);
    }
}
without that extra line of code your team is proposing that says, "No seriously, that variable you defined named 'text' is really a variable you defined named 'text'". The proposed effect is to push a new kind of repetition into the language, when this sort of "restate the obvious" repetition is something almost every version of C# from 2.0 onwards has tried to stamp out!

Make those primary constructor variables into private fields and get on with things. Maybe add a "readonly" keyword. This "initializer scope" business sounds like a lot of complication that delivers no benefit outside of perhaps smoothing out the DTO scenario.

But there's another scenario which needs just as much attention: Dependency Injection. C# remains one of the most DI-hostile languages I can think of, due to the need to state the name of every injected object FOUR times and every injected object type TWO times. As proposed, primary constructors without initializer scope would reduce this to ONE and ONE.
May 21, 2014 at 12:22 PM
Aw man, the indexed members is what I was most excited about from reading this article. Please consider bringing them back. :)
http://msdn.microsoft.com/en-us/magazine/dn683793.aspx
May 21, 2014 at 11:10 PM
I really like the idea of using a keyword (constructor) for constructor bodies (including the primary one) and reducing repeated names while making the primary constructor body obvious.

I think the params keyword is unnecessary.

In class Point(int X, int Y); I don't see why the properties should be get only. Why not combine the field parameter thinking so far with auto-implemented properties to get class Point(public readonly int X, public readonly int Y); to with the obvious changes for get+set while leaving private field parameters fields?
May 21, 2014 at 11:46 PM
Obvious question here... but why not make these new features modularized? That is, make it possible for a developer (or team) to decide which features (sugar) to enable with their compiler? That way everyone gets what they want... and they can furthermore add their own modules to the compiler to make it even better (or worse haha). Just a thought.
May 22, 2014 at 12:38 AM
MichaelDBang wrote:
Obvious question here... but why not make these new features modularized? That is, make it possible for a developer (or team) to decide which features (sugar) to enable with their compiler? That way everyone gets what they want... and they can furthermore add their own modules to the compiler to make it even better (or worse haha). Just a thought.
We prefer to define one language per release rather than 2^n languages per release. Makes it much easier for us to support the language and for people to understand each other's code.
May 22, 2014 at 12:56 AM
Edited May 22, 2014 at 2:46 PM
I like the proposed syntax for Indexed members. Yes, it's syntactic sugar with a limited use-case but it's a clean syntax that can save some typing in certain situations without obfuscating the intent or affecting existing C# code. it seems like most of the objections are really rooted in discomfort with a further syntactic divergence with existing C++/java derived languages whereas i see this as a further move to take the best of the dynamic language world and enable it'e efficient and statically typed usage within C#.
May 22, 2014 at 3:28 AM
sdedalus2000 wrote:
I like the proposed syntax for Indexed members. Yes, it's syntactic sugar with a limited use-case but it's a clean syntax that can save some typing in certain situations without obfuscating the intent or effecting existing C# code. it seems like most of the objections are really rooted in discomfort with a further syntactic divergence with existing C++/java derived languages whereas i see this as a further move to take the best of the dynamic language world and enable it'e efficient and statically typed usage within C#.
Right now one can do the following:
myClass["cheese"]  //where "cheese" can be any object, not limited to strings
myClass.cheese //with dynamic typing
How is the following in any meaningful way superior?
myClass.$cheese
May 22, 2014 at 12:53 PM
$cheese would be superior in that it as a legitimate bonafide symbol to a known type (string), rather than messing (casting) with dynamic. Dynamic as you suggest is close, but it's clunky. $ would address that and make it a stronger symbol.
May 22, 2014 at 1:38 PM
MichaelDBang wrote:
$cheese would be superior in that it as a legitimate bonafide symbol to a known type (string), rather than messing (casting) with dynamic. Dynamic as you suggest is close, but it's clunky. $ would address that and make it a stronger symbol.
Except that it's not a "bonafide symbol", it's just barely shorthand for indexing by a string which we can do just fine already. The .$ operator does nothing except confuse that fact and save a whopping 2 characters. It always felt dirty in VB and it wouldn't solve any problems at all.
May 22, 2014 at 1:43 PM
I should say it's "bonafide" from a tooling perspective. Can you "rename" a string?
May 22, 2014 at 1:44 PM
@Halo_Four, @NPSF3000 What does Intellisense show you when you hover over myClass["cheese"]? What autocompletion does the IDE provide when you start typing myClass["c...? How about for an expression like myClass["cheese"]["nacos"]?

This was the point of the feature, to treat string indexers as lightweight member access so you can get autocompletion and Intellisense without the runtime overhead of using dynamic (which is significant). Right now indexers are annoying to use as there's no "right" place to put the mouse to even find the return type of the indexer via Intellisense.
May 22, 2014 at 1:48 PM
Edited May 22, 2014 at 1:50 PM
@MgSam: Or, instead of adding new language features, Microsoft could just fix the IDE in the cases you've mentioned. Additionally, if the IDE can figure out that it should offer you to complete x.$a to x.$abcd it should also be able to figure out that you can complete x["a to x["abcd"] since the former is syntactic sugar for the latter.
May 22, 2014 at 1:59 PM
Expandable wrote:
@MgSam: Or, instead of adding new language features, Microsoft could just fix the IDE in the cases you've mentioned. Additionally, if the IDE can figure out that it should offer you to complete x.$a to x.$abcd it should also be able to figure out that you can complete x["a to x["abcd"] since the former is syntactic sugar for the latter.
The IDE gets its language services from Roslyn. So Roslyn would need to specifically handle string indexers anyway. This might work for autocompletion, but it still seems rather weird. After all, why should the IDE autocomplete a string just because its in an indexer; you might actually be intending to write a different but similar string than one you typed out earlier. Intellisense is even more problematic. Having something other than System.String pop up when you hover over a string seems very weird.

With the .$ syntax your intention is explicit. The language services don't have to make any guesses.
May 22, 2014 at 2:17 PM
MgSam wrote:
Expandable wrote:
@MgSam: Or, instead of adding new language features, Microsoft could just fix the IDE in the cases you've mentioned. Additionally, if the IDE can figure out that it should offer you to complete x.$a to x.$abcd it should also be able to figure out that you can complete x["a to x["abcd"] since the former is syntactic sugar for the latter.
The IDE gets its language services from Roslyn. So Roslyn would need to specifically handle string indexers anyway. This might work for autocompletion, but it still seems rather weird. After all, why should the IDE autocomplete a string just because its in an indexer; you might actually be intending to write a different but similar string than one you typed out earlier. Intellisense is even more problematic. Having something other than System.String pop up when you hover over a string seems very weird.

With the `.MgSam wrote:
syntax your intention is explicit. The language services don't have to make any guesses.
The intention is identical between the two of them. This syntax isn't just for referencing existing members but also to add new members. The language service would still have to try to figure out if it knows what indexes might be in there in order to show any list and if that dictionary is coming from any other source that becomes effectively a moot point anyway. And in the end the language service is still not going to know if the developer wanted an existing index or if the developer wanted to type a new index, so that problem remains exactly the same.

Either way, dead horse, and thankful for it. It was never good practice in VB despite it having the same feature for decades.
Aug 5, 2014 at 2:16 AM
I just want to add my support for cutting primary constructors.
With the multiple implied scopes and other issues it becomes much harder to understand something that was previously very simple all for minimal savings.