Changes to the language feature set

Topics: C# Language Design, VB Language Design
Coordinator
Oct 1, 2014 at 9:17 PM
Hi all,

As we enter the final stage in our long quest to renew the C# and Visual Basic experience, we’ve had to make some tough decisions around the set of language features that will make it into the next version of the languages.

These decisions are primarily based on cost vs. risk. Some of the features you’ve seen in the previews still need a lot of downstream work to be supported in the IDE, debugger, etc., and also to get to great quality in the compiler itself.

As you’ve maybe heard me say before, language features are a secondary consideration in this release. The primary goal is to deliver a magnificent first release of the Roslyn value proposition: deep language understanding in the IDE and available to everyone through a robust and comprehensive API. To deliver this well, we need to scale back our appetite for language features a bit.

The features we are cutting are:
  • Primary constructors in C# (along with initializers in structs)
  • Declaration expressions in C# / Out parameters in VB
They are both characterized by having large amounts of downstream work still remaining. They are also features that we see as the potential beginning of a bigger story further down the line: primary constructors could grow up to become a full-blown record feature, and declaration expressions would form the corner stone of pattern matching and deconstruction facilities. Now, those features will all be considered together for a later release. As a silver lining we then get to design this continuum holistically, rather than in steps that might tie our hands unduly in a later phase.

All that said, I am sad to let these features go, and I know that goes for many of you as well. You’ve provided amazingly valuable feedback on both these features, and those learnings will feed directly into our future design work. I cannot thank you enough for this incredible engagement! I also hope you’ve enjoyed seeing more of the “inner workings” this time around, even if it leads to disappointment when you watch things come and go in our plans. Your increased involvement has certainly been rewarding for us, and – we hope! – helped improve the quality and timeliness of our decisions.

There’s a bit of good news too: string interpolation (which hasn’t been previewed yet) is currently looking to make it in. You should see that one show up first in C# (where we’ve already prototyped our approach), and a little later in VB.

Thanks again!

Mads
Oct 1, 2014 at 9:42 PM
Will the open Bugs of Rosly be fixed before the release? Very important for me is fixing of https://roslyn.codeplex.com/workitem/264
Developer
Oct 1, 2014 at 10:34 PM
Took a look at that bug, and we are planning to have it fixed before release.
Oct 1, 2014 at 11:20 PM
For the next VNext - can the language in the status be altered so that "done" means "done and we think it will be in".

Hearing that a feature that was marked as "done" still has "large amounts of downstream work to be remaining" feels like a shortcoming in communication, even if I know by "downstream work" you mean "other teams" Which of course is quite a surprise if you've used these features and feel that it already has complete support in VS and the debugger.

And can you give an updated value proposition on auto-property initializers and getter-only auto-properties as it seems they have very little value when there is no data available without initialization scope..

I'm about ready to go be a truck-stop waitress I'm so bummed, but I trust that you all have the broader view.

Kathleen
Oct 1, 2014 at 11:29 PM
Edited Oct 1, 2014 at 11:29 PM
Pattern matching in C# 7 promise it now!
Oct 2, 2014 at 12:11 AM
Honestly I'm glad to see that primary constructors are getting delayed. I understand where it was coming from but the whole thing morphed from a simple syntax for a simple use case to a full-fledged alternate syntax for class definitions with a nasty syntax and bizarre scoping rules. It crossed the line from "succinct" to "terse". I think that when designed with pattern matching and record types in mind that the feature could find new life but I hope that it doesn't succumb to the same pressures to make it functionally on par with the current class syntax.

I'm a little sad to see variable declarations dropped. I think that the concept has a usefulness outside of pattern matching such as with the variety of Try* methods that exist. I imagine that it was a question of timing and maybe still some controversy over design decisions as witnessed by the fact that the thread for the last meeting notes is still fairly active. Personally I have a few nits to pick about the scoping rules, but whatever. With pattern matching in mind I'm sure that it could be extended to do some interesting stuff, and I do think that functionality like being able to use a pattern matching wildcard operator would be useful for those out parameters the developers might want to ignore/discard.

Anywho, the good news here is that the cycle for C# 6.0 is coming to a close which I hope means that we can anticipate Roslyn and Visual Studio shipping sooner rather than later. I'd love to hear news about what may be expected in the next cycle but I'm sure that there is a lot left to be done before than can of worms is opened. Thanks for all of the hard work!
Oct 2, 2014 at 1:29 AM
I'm glad primary constructor is gone too. The record feature may be a better start than primary constructor.
Oct 2, 2014 at 5:52 AM
I'm extremely relieved to see declaration expressions removed. The side-effect design decisions that needed to be made were not worth the marginal gain of the feature. There are currently over 100 mentions of the word "shadow" in September's discussion notes: https://roslyn.codeplex.com/discussions/565640

I'm also glad to see primary constructors removed as I didn't feel they brought enough to the table to warrant implementing.

Overall, I'm glad to see features were not just added for the sake of adding features. The C# Language is great because of the thought that goes into each new feature, nothing is added just because it can be.

Thanks to the team for opening up discussions. Keep up the good work.
Oct 2, 2014 at 8:02 AM
Great news, and I say that as someone who's wanted out int x since the first time I encountered out.

I understand why primary constructors were invented, but they added another layer of identifier origin, scope, visibility and lifetime and didn't really deliver anything on top. They only delivered syntactical sugar, at too high a cost of complexity. I love syntactical sugar as long as it's clear, crisp and localized, but primary constructors affected semantics across the entire type declaration. It makes sense to me that this gets cut, and after the pattern matching discussions, I look forward to a record or record-like idea where the ideas that primary constructors support can be provided more naturally and concisely while also fitting in well with entirely new capabilities.
Oct 2, 2014 at 8:52 AM
Edited Oct 3, 2014 at 9:08 PM
I'm also glad to see that primary constructors are gone. While I initially liked them, the more I thought about them and the more you complicated the rules, the more bothered by them I became. They just "felt" wrong, for some reason. I do like the pattern matching/record proposal though, so I'm glad that you're considering everything together. I'm convinced that this approach will lead to a better implementation in the end.

As for declaration expressions, that too seemed to be very nice at first, but started "feeling" wrong when the discussion about scoping came up.

So all in all, thanks for having the courage to do the right thing here. I'm absolutely certain that it was the right decision to make. Though I do agree with Kathleen, you should probably mark features which might not make it into the final release more clearly (especially not "Done", maybe "Experimental" or "Prototyped"?). For instance, the Resharper guys have apparently put a lot of work already into the next version of Resharper to support primary constructors....

@Kathleen: As for getter-only auto-properties and property initializers: True, their usefulness is somewhat reduced by the removal of primary constructors. Still, I often find myself wanting to initialize auto-properties (for instance, a bool property that should have a default value of true), so I can still write bool MyProp {get;set;} = true; now, potentially avoiding having to create a constructors just for that. So in my opinion, the feature is still very useful.

The usefulness of getter-only properties, however, has not been reduced much by the removal of primary constructors. Their main purpose, after all, is to save you from having to write a non-auto property returning an explicitly declared readonly field, which has nothing to do with primary constructors. Only their initialization is affected by the cut of that feature, but that is true for all auto-properties. And remember that you can still assign any value to getter-only properties within constructors.
Oct 2, 2014 at 9:51 AM
I agree partially with Kathleen and Expandable: labeling of upcoming features should be solid. That said, it didn't appear to me that they really were more tentative than any other feature. What I think I saw is that the system worked: the prototype, community and ecosystem made it easier to decide that it was going to be a problem. Regardless of what you think you know about a feature, design issues can always crop up at an inopportune stage and I'd rather they'd be able to shelve it with some immediate mess than have to ship something they'd have to support until the end of time.

I am also choosing to see this as a vestige of the transition from closed to open. Take pattern matching - we know that it is on the cards for the next version of C# beyond the one currently in development at the earliest. Discussions are being held right now and language design is not a black box. Primary constructors were among the first generation and were partially decided and mostly set in secret and it would have taken an uphill battle to replace it with a slightly different design after it had already been announced. It doesn't look like this is going to happen to features going forward, or at least to a much smaller degree.
Oct 2, 2014 at 1:15 PM
I agree with both decisions.

Primary constructors are a nice feature that may save a few lines, but the record proposal has the makings of being a game-changer in the way types are designed and implemented, saving dozens of lines of code. I'd rather see the record syntax be the starting point and primary constructors designed as an outgrowth of that, not the other way around.

Declaration expressions also looked good on paper, but after the last language design committee decision to eliminate spill-out the feature became practically useless. When some of the only valid examples of using a feature are themselves anti-patterns, you really have to question whether you have the right design. I think keeping pattern-matching in mind is also the right place to implement this feature correctly.

Finally, I'd just like to reiterate my hope that the more open development process and the de-coupling of C# versions to .NET versions allows the language design team to iterate more quickly in the future. It sucks waiting 3 years between versions of C#, especially so when terrific features like records and pattern matching are on the horizon (and already implemented in a prototype!). I'd rather see these features released as a C# 6.5 in 1-1.5 years rather than be packaged up with a bunch of unrelated features and put on the shelf for another major release. Apple via Swift have leap-frogged C# with some really nice, modern features. C# needs to evolve more rapidly and catch up!
Oct 2, 2014 at 4:47 PM
I also agree with the decision to withdraw these two features. Both had some unpleasant "smells" associated with them. As for language feature status, perhaps you need both "done" and "done done". :-)

@MgSam Out of curiosity, what are some of these Swift leap-frog features?
Oct 2, 2014 at 7:37 PM
What of the other features listed as Planned or Maybe on the Language Feature Status page? Are those still slated to be released with C# 6.0 or is that page tracking language features irrespective of version? Most of the remaining Maybes haven't had a lot of exposure on these forums, perhaps because they're conceptually simple.
Oct 2, 2014 at 8:07 PM
To my mind, primary constructors, if properly implemented, would have brought C# one step closer to being a "semantically complete" language for writing managed code in .NET (meaning one where any meaningful managed-code semantics which can be created in CIL could be created in C#), but certain aspects of the planned implementation would have not only fallen severely short in that regard, but probably made it more difficult to fill in the semantic weaknesses in a future version of C#.

A good language/framework should not require the use of two-phase object construction (i.e. having a constructor return an object that can't do anything useful until a separate Initialize method is called). If a class invariant requires that each instance be permanently attached to a parent instance from which it may receive events, that invariant should be established before the constructor returns. In CIL this would pose no problem, since derived classes could establish their own subclass invariants before chaining to the main constructor, but it is very difficult in C# for a derived class to establish, before chaining the base constructor, any invariants which depend upon constructor parameters. There are ways of kludging such things using ThreadStatic variables, but they're nasty. There shouldn't be any difficulty with enhancing primary constructors' abilities to establish invariants, but I don't think such issues were really considered.
Coordinator
Oct 2, 2014 at 10:08 PM
@supercat I don't understand. First you were talking about setting up instance relationships so that some other instance can point to the new class you've constructed before the constructor returns. But next you talked about base class initialization (presumably of the same instance). What you then described sounded to me like Swift, whose order of construction and definite assignment feels more unpleasant: http://swiftopinions.wordpress.com/2014/09/29/to-swift-and-back-again/
Oct 2, 2014 at 11:16 PM
lwischik wrote:
@supercat I don't understand. First you were talking about setting up instance relationships so that some other instance can point to the new class you've constructed before the constructor returns. But next you talked about base class initialization (presumably of the same instance). What you then described sounded to me like Swift, whose order of construction and definite assignment feels more unpleasant: http://swiftopinions.wordpress.com/2014/09/29/to-swift-and-back-again/
Setting up hierarchical relationships of instances (whose classes may or may not be related) requires that the class responsible for establishing the relationship either do so in its own constructor or else require a semantically-ugly two-step construction protocol. A class which sets up the relationship in its constructor poses a problem for derived classes under C#, since the base class constructor will expose a reference to an object whose derived-class constructors haven't even had a chance to access their constructor parameters.

Thanks for the article on Swift. What I would want to see would be an optional feature similar to what Swift mandates. If a field isn't declared readonly, or isn't written by a partial constructor, then a derived class could write to the field whenever it would be convenient for it to do so [I suppose for purposes of interfacing with existing code, one could use a new keyword to allow for the possibility of an old-style readonly variable being set in a constructor, but that's a minor issue].

Incidentally, on a related note, I wish there were a means by which constructors and methods could separately specify their visibility for purposes of use with instances of its own type vs. derived types. If a class could offer a public constructor which could only be used for offering instances of its own type, then outside-callable constructor could attach the newly-constructed object to the parent, while the chained constructor could specify in its contract that the derived-class was responsible for either doing that or passing the responsibility to a sub-derived class. Such a design could also be helpful in cases where every derived-type constructor was required to pass information related to itself to the base constructor (a parameterless constructor might be suitable for outside code constructing a base-class instance, but not for any derived class constructing a derived-class instance). A similar issue could arise with methods: a class might know that its implementation of a virtual method is a good implementation for instances of itself, but could not legitimately be used by any derived-class. It would in such cases be helpful to be able to regard a method as being virtual with regard to instances of the base class, but virtual with regard to the derived class. I don't think the .NET Framework has the hooks needed to make such a distinction, but IMHO they would be useful.
Coordinator
Oct 3, 2014 at 1:00 AM
Halo_Four wrote:
What of the other features listed as Planned or Maybe on the Language Feature Status page?
The page only tracks C#6 and VB14. I've updated it! Thanks for the heads up.
Oct 3, 2014 at 1:14 AM
lwischik wrote:
Halo_Four wrote:
What of the other features listed as Planned or Maybe on the Language Feature Status page?
The page only tracks C#6 and VB14. I've updated it! Thanks for the heads up.
Wow, binary literals and digit separators didn't make the cut? What's the story there?

Very sad to see constructor inference isn't making it, as repeating types for constructors is a constant annoyance.
Coordinator
Oct 3, 2014 at 1:19 AM
MgSam wrote:
Wow, binary literals and digit separators didn't make the cut? What's the story there?
Time and schedule pressure, nothing more! Same reason I'm sitting here filing bugs on the ?. operator in VS14 CTP3 rather than home playing with my baby daughter!
Developer
Oct 3, 2014 at 5:39 AM
KathleenDollard wrote:
can you give an updated value proposition on auto-property initializers and getter-only auto-properties as it seems they have very little value when there is no data available without initialization scope..
You can now assign to getter-only autoprops in the constructor. That causes assignment to the backing field.
Oct 3, 2014 at 11:51 AM
After looking at implementation status, I see you are strongly favour C# at expense of VB. Especially Expression-bodied members is very missing for me, and ? operator is not sure. Hope that you remove these disparities with VS 14 update, than next verion.
Oct 3, 2014 at 1:42 PM
I always thought C# 6.0 features were kind of "meh". I even actively disliked the initially announced design of primary constructors. As a big fan of pattern matching and someone who has pattern matching at the very top of the C# features wishlist I applaud the decision to design both features around pattern matching. Pattern Match all the things! Please consider tuple syntax support suitable for pattern matching along with records and declaration expressions.

The insight into the language design process was extremely interesting to me and I wish you continue to make it public. I do not even care that much about giving feedback I just like reading the thought process.

Thank you for the hard work.
Oct 3, 2014 at 3:13 PM
Thanks for the update! It looks like "params IEnumerable<T>" is the only C# 6 feature that is still a "maybe". I'm not sure what that means, so I thought I'd give it a plug. I'm tired of writing "params T[]" overloads that delegate to "IEnumerable<T>" methods! :-)
Coordinator
Oct 3, 2014 at 3:55 PM
codefox wrote:
After looking at implementation status, I see you are strongly favour C# at expense of VB. Especially Expression-bodied members is very missing for me, and ? operator is not sure. Hope that you remove these disparities with VS 14 update, than next version.
Codefox, actually we in the VB language design meeting are very proud of what's in VB! The work done for VB in this release that wasn't done for C# includes
  • Multiline string literals (catchup to C#)
  • Year-first date literals
  • Comments have been fixed up with line continuations
  • XML Doc-comments now work properly (mostly catchup to C#)
  • TypeOf IsNot
  • Partial modules
  • Partial interfaces (catchup to C#)
  • #region now allowed (catchup to C#)
  • #Disable Warning (catchup to C#)
  • Readonly props in interface can be implemented by readwrite props (catchup to C#)
  • Overloads Overrides works better
  • Attribute arguments now allow boxing (catchup to C#)
Sure a lot of them were catchup. But that just shows that VB had a lot of work needed, which we've largely done.

Note that the ?. operator has already been implemented in VB (not in time for CTP4, but will appear after that). It's just not quite 100% complete - throws an exception in some cases, pretty-lists wrong in other cases.

As for expression-bodied function members, we discussed them here: https://roslyn.codeplex.com/discussions/540509
See item "40. Expression-bodied function members"

We explored a whole bunch of different possible VB syntaxes for expression-bodied function members, but as we wrote "RESOLUTION: We're proud not to do anything. None of the proposals buy that much, and none are that special."

If you have other ideas, or want to re-open the discussion about one of the ideas we came up with, please do!
Coordinator
Oct 3, 2014 at 4:02 PM
ejball wrote:
Thanks for the update! It looks like "params IEnumerable<T>" is the only C# 6 feature that is still a "maybe". I'm not sure what that means, so I thought I'd give it a plug. I'm tired of writing "params T[]" overloads that delegate to "IEnumerable<T>" methods! :-)
We're tired of writing it too! Our schedule masters say that Params IEnumerable is a "no" due to schedule pressure. But we love it so much that I couldn't bear to write the words "no" there. Seemed too final.
Oct 3, 2014 at 8:47 PM
Expandable,

Yes, I was confused about the usefulness of getter-only auto-properties without primary constructors because I was experimenting with the current CTP that does not support assigning getter-only auto-properties in the constructor.

When that is fixed, you are correct, the value of getter-only auto-props is not affected by the loss of primary constructors.

Kathleen
Oct 3, 2014 at 11:28 PM
lwischik wrote:
ejball wrote:
Thanks for the update! It looks like "params IEnumerable<T>" is the only C# 6 feature that is still a "maybe". I'm not sure what that means, so I thought I'd give it a plug. I'm tired of writing "params T[]" overloads that delegate to "IEnumerable<T>" methods! :-)
We're tired of writing it too! Our schedule masters say that Params IEnumerable is a "no" due to schedule pressure. But we love it so much that I couldn't bear to write the words "no" there. Seemed too final.
How might the community fit into that? I could see external effort contributing to some of those potentially lower-hanging fruit like params IEnumerable<T>, digit separators or binary literals and the potential of it being pushed to the next cycle might be motivation to get moving on that. I do imagine that the Roslyn team would be insanely rigorous in terms of evaluating pull requests, as they absolutely should be, but perhaps some of the tedium could be alleviated from the team proper.
Oct 3, 2014 at 11:57 PM
A lot of the these features where in the VS2013 Roslyn CTP, Suddenly they are not in the next release?

If Roslyn all about better understanding and manipulation of your code. wouldn't it be a good idea to implement an analyser to do the conversion / upgrade for you?
Oct 4, 2014 at 12:05 AM
@lwischik
Thanks for clarification. No doubt you made solid progress. I am happy that ? operator will be implemented.

Current single line labdas are great in functions. But it is impossible to write:
Class C
    Public Square(x As Integer) x*x
End Class
in VS 2013 and VS 14 CTP3.

Possible is to write:
Class C
    Public Square As Func(Of Integer, Integer) = Function(m As Integer) m * m
End Class
which is bit too long. Type inference is needed here.

As for other ideas i have sent few of them:
https://roslyn.codeplex.com/discussions/542995
https://roslyn.codeplex.com/discussions/561381
https://roslyn.codeplex.com/discussions/542794
In order of importance, and
https://roslyn.codeplex.com/discussions/544710
in longer term.
Oct 4, 2014 at 12:14 AM
Edited Oct 4, 2014 at 12:15 AM
@codefox

Lambdas can be one of two types. Let me us your lambda for example could be either Func<Int, Int> or Expression<Func<Int, Int>>

I think inference should be more biased towards inferring the first.
Would the inference work for recursive lambda definitions.
Coordinator
Oct 4, 2014 at 6:11 PM
AdamSpeight2008 wrote:
A lot of the these features where in the VS2013 Roslyn CTP, Suddenly they are not in the next release? If Roslyn all about better understanding and manipulation of your code. wouldn't it be a good idea to implement an analyser to do the conversion / upgrade for you?
Alas that won't work very well... the analyzer gets to see syntax trees for code that it can parse. But once the features have been removed, then the code no longer parses, and analyzers will just get unparsed chunks of error text to work with. It'll be hard to write an analyzer that recognizes now-invalid syntax.
Coordinator
Oct 4, 2014 at 6:20 PM
Halo_Four wrote:
How might the community fit into that? I could see external effort contributing to some of those potentially lower-hanging fruit like params IEnumerable<T>, digit separators or binary literals and the potential of it being pushed to the next cycle might be motivation to get moving on that.
That's a great question. When we put together our "priority list" of what features give the most bang-for-the-buck for us to implement in the next release, we looked at the list of features below the cutline and said exactly what you said: how great it would be to accept pull-requests to add these language features. However there's still some figuring-out to do before that. The figuring-out is:

(1) What cadence is best to release language features? Can they come out in a VS Update or should they wait for a major new VS version? If they come out in a VS Update, what do we do about teams where some of the devs have installed the update but others haven't? Some VB/C# users like to be on the cutting edge and adopt new features as soon as they come out. Others sigh with resentment because each new language feature means they have to take a week away from their work to learn the new features, establish team guidelines, and teach the rest of their team about them.

(2) All of the features will need some rudimentary IDE support (colorizing, intellisense). Others might impact more IDE stuff (find-all-references, ...). While the compilers are OSS, the IDE layer isn't. How would we manage this? Would we take in a pull-request with the compiler-features, and then do the rest of the IDE stuff ourselves? How will we make sure that compilers and IDE stay in sync?


This is figuring out that we want to do, but we're going to put on the back burner just at the moment while we work on VS14.
Oct 4, 2014 at 9:48 PM
lwischik wrote:
If they come out in a VS Update, what do we do about teams where some of the devs have installed the update but others haven't? Some VB/C# users like to be on the cutting edge and adopt new features as soon as they come out. Others sigh with resentment because each new language feature means they have to take a week away from their work to learn the new features, establish team guidelines, and teach the rest of their team about them.
I don't think that's a question that your team can or should try to answer.

You can easily set the language target in any project you make. I don't see how releasing language updates at a faster pace changes that. Teams should decide for themselves whether they want to be cutting edge or stick to one established version. The same sort of decision that they're already making with the VS updates.
(2) All of the features will need some rudimentary IDE support (colorizing, intellisense). Others might impact more IDE stuff (find-all-references, ...). While the compilers are OSS, the IDE layer isn't. How would we manage this? Would we take in a pull-request with the compiler-features, and then do the rest of the IDE stuff ourselves? How will we make sure that compilers and IDE stay in sync?
Keep pounding on the door of those upstairs until the VS layer can be open-sourced as well. Web Essentials is totally open source, yet it still provides a major competitive advantage for VS.
Oct 5, 2014 at 7:45 AM
Edited Oct 5, 2014 at 7:47 AM
May I make one more request, only semi-related to this announcement? I see you guys are working hard to get features implemented and bugs fixed. I've also noticed that Roslyn has only received 18 pull requests.

Open the internal bug tracking system. (Or exclusively use Issues)

Right now it's really hard to contribute to Roslyn as the Issues are poorly curated. Some are feature requests, some are wrong, and some are genuine bugs that are being tracked internally. If it were easier to see what bugs were up for grabs, I think you'd see a lot more engagement from the community.

Note: It might be too late for this release, adding new programmers to a project slows it down and worrying about external pull requests might also slow things down

Thanks again for all your hard work. We really appreciate all that you guys have done and are doing.
Oct 6, 2014 at 9:26 PM
Understand, but still missing out param declarations :-(
Oct 6, 2014 at 9:51 PM
Edited Oct 6, 2014 at 9:51 PM
pazucha wrote:
Understand, but still missing out param declarations :-(
I feel your pain!
Oct 6, 2014 at 10:21 PM
lwischik wrote:
Halo_Four wrote:
How might the community fit into that? I could see external effort contributing to some of those potentially lower-hanging fruit like params IEnumerable<T>, digit separators or binary literals and the potential of it being pushed to the next cycle might be motivation to get moving on that.
There are quite a few things which would seem like they should be relatively low-hanging fruit; indeed, some--like removing the prohibition against the use of System.Enum or System.Delegate as constraints--would require for implementation nothing more than commenting out a couple lines in the compiler. Of course, even such simple things might require some careful analysis to ensure they don't open up any weird corner cases, but I'm not sure what would be required to achieve a consensus that the changes wouldn't cause any problems.
Coordinator
Oct 7, 2014 at 12:26 AM
Edited Oct 7, 2014 at 12:27 AM
supercat wrote:
There are quite a few things which would seem like they should be relatively low-hanging fruit... Of course, even such simple things might require some careful analysis to ensure they don't open up any weird corner cases, but I'm not sure what would be required to achieve a consensus that the changes wouldn't cause any problems.
From my experience with past language features, the best way to achieve acceptance is
  1. Compelling evidence that the feature solves a real end-user need far better than any workaround. This is the bit that most people don't focus hard enough on. At the language design meetings, if we haven't seen something as a real problem in our own coding, or haven't seen comments from the public that persuade us that it's an actual real concrete problem, or haven't seen feedback on uservoice or from audiences at talks, then we'll often say "no".
  2. Survey of related problems that might be solved by a more general mechanism, so as to decide whether it's better to use a general mechanism or a specific one for this particular need.
  3. Survey of how the problem is solved in other languages, either languages used in industry or prototype languages that come from academia.
  4. A working prototype, because the act of writing the prototype invariably uncovers language design issues that no one had even thought of before. Also to uncover downstream IDE work that will have to be done.
  5. A working prototype, so people can play with it for real and see how it works.
  6. Review by some of the "test geniuses", the people who know ever last corner of the language and every oddity.
In my mind the true low-hanging-fruit are the ones that have really simple answers to 1,2,3 (e.g. binary literals, digit separators, params IEnumerable).


-- Lucian Wischik, VB/C# language design team (folks have asked for more clarity on who is in the MS team...)
Oct 7, 2014 at 5:29 AM
Too bad Strict Modules didn't make it in.
Oct 7, 2014 at 5:50 AM
supercat wrote:
There are quite a few things which would seem like they should be relatively low-hanging fruit; indeed, some--like removing the prohibition against the use of System.Enum or System.Delegate as constraints--would require for implementation nothing more than commenting out a couple lines in the compiler. Of course, even such simple things might require some careful analysis to ensure they don't open up any weird corner cases, but I'm not sure what would be required to achieve a consensus that the changes wouldn't cause any problems.
Given that statement, just out of curiosity, how would you use these constraints in C# (or VB)?
Oct 7, 2014 at 3:04 PM
Edited Oct 7, 2014 at 3:04 PM
PauloMorgado wrote:
Given that statement, just out of curiosity, how would you use these constraints in C# (or VB)?
For enum:
internal static class EnumHelper<T1>
{
    public static Func<T1, T1, bool> TestOverlapProc = initProc;
    public static bool Overlaps(SByte p1, SByte p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(Byte p1, Byte p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(Int16 p1, Int16 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(UInt16 p1, UInt16 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(Int32 p1, Int32 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(UInt32 p1, UInt32 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(Int64 p1, Int64 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(UInt64 p1, UInt64 p2) { return (p1 & p2) != 0; }
    public static bool initProc(T1 p1, T1 p2)
    {
        Type typ1 = typeof(T1);
        if (typ1.IsEnum) typ1 = Enum.GetUnderlyingType(typ1);
        Type[] types = { typ1, typ1 };
        var method = typeof(EnumHelper<T1>).GetMethod("Overlaps", types);
        if (method == null) throw new MissingMethodException("Unknown type of enum");
        TestOverlapProc = (Func<T1, T1, bool>)Delegate.CreateDelegate(typeof(Func<T1, T1, bool>), method);
        return TestOverlapProc(p1, p2);
    }
}
static class EnumHelper
{
    public static bool Overlaps<T>(this T p1, T p2) where T : struct
    {
        return EnumHelper<T>.TestOverlapProc(p1, p2);
    }
}
Enum1.Overlaps(Enum2) behaves like Enum1.HasFlag(Enum2) but about 30x faster, reducing the speed penalty to the point that it should in most contexts be considered a good substitute for (Enum1 & Enum2) != 0. It's also typesafe when applied to an enum. Unfortunately, IntelliSense offers it for all value types, even those for which it won't work. If enum constraints were available, I'd also define HasAllFlags (test whether (~it & other)==0), and maybe a Has which which would return a structure with a ButNot method (thus Enum1.Has(Enum2).ButNot(Enum3) would be equivalent to (Enum1 & Enum2) != 0 && (Enum1 & Enum3) == 0).

With regard to delegates, how about:
T CombinedWith<T>(this T it, T other);
T Without<T>(this T it, T other);
void SafeAttachBefore<T>(this T it, ref T other);
void SafeAttachAfter<T>(this T it, ref T other);
void SafeDetach<T>(this T it, ref T other);
I hope ?. works with members that don't return a value, since I expect by far the number 1 usage case would be someEvent?.Invoke(params), but it not one could probably improve the convenience of delegate invocation with:
T ValueOrDefault<T>(this T it);
T ValueOrDefault<T>(this T it, T alternate);
The second would return it if not null, or else return alternate. The first would return it if not null, or else use Reflection to generate a method that does nothing and returns a default value of the appropriate type, thus allowing SomeDelegate.ValueOrDefault()(params) [the first delegate of any particular type would be cached, and used as the default for future calls].

I don't think there are necessarily a huge number of methods or classes using such constraints, but I would expect that some such classes or methods would receive very wide use if they existed.
Oct 8, 2014 at 12:48 AM
supercat wrote:
PauloMorgado wrote:
Given that statement, just out of curiosity, how would you use these constraints in C# (or VB)?
For enum:
internal static class EnumHelper<T1>
{
    public static Func<T1, T1, bool> TestOverlapProc = initProc;
    public static bool Overlaps(SByte p1, SByte p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(Byte p1, Byte p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(Int16 p1, Int16 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(UInt16 p1, UInt16 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(Int32 p1, Int32 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(UInt32 p1, UInt32 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(Int64 p1, Int64 p2) { return (p1 & p2) != 0; }
    public static bool Overlaps(UInt64 p1, UInt64 p2) { return (p1 & p2) != 0; }
    public static bool initProc(T1 p1, T1 p2)
    {
        Type typ1 = typeof(T1);
        if (typ1.IsEnum) typ1 = Enum.GetUnderlyingType(typ1);
        Type[] types = { typ1, typ1 };
        var method = typeof(EnumHelper<T1>).GetMethod("Overlaps", types);
        if (method == null) throw new MissingMethodException("Unknown type of enum");
        TestOverlapProc = (Func<T1, T1, bool>)Delegate.CreateDelegate(typeof(Func<T1, T1, bool>), method);
        return TestOverlapProc(p1, p2);
    }
}
static class EnumHelper
{
    public static bool Overlaps<T>(this T p1, T p2) where T : struct
    {
        return EnumHelper<T>.TestOverlapProc(p1, p2);
    }
}
Enum1.Overlaps(Enum2) behaves like Enum1.HasFlag(Enum2) but about 30x faster, reducing the speed penalty to the point that it should in most contexts be considered a good substitute for (Enum1 & Enum2) != 0. It's also typesafe when applied to an enum. Unfortunately, IntelliSense offers it for all value types, even those for which it won't work. If enum constraints were available, I'd also define HasAllFlags (test whether (~it & other)==0), and maybe a Has which which would return a structure with a ButNot method (thus Enum1.Has(Enum2).ButNot(Enum3) would be equivalent to (Enum1 & Enum2) != 0 && (Enum1 & Enum3) == 0).
Interesting.

And all those Overlaps overloads are screaming for more features you've been asking for.
With regard to delegates, how about:
T CombinedWith<T>(this T it, T other);
T Without<T>(this T it, T other);
void SafeAttachBefore<T>(this T it, ref T other);
void SafeAttachAfter<T>(this T it, ref T other);
void SafeDetach<T>(this T it, ref T other);
I hope ?. works with members that don't return a value, since I expect by far the number 1 usage case would be someEvent?.Invoke(params), but it not one could probably improve the convenience of delegate invocation with:
T ValueOrDefault<T>(this T it);
T ValueOrDefault<T>(this T it, T alternate);
The second would return it if not null, or else return alternate. The first would return it if not null, or else use Reflection to generate a method that does nothing and returns a default value of the appropriate type, thus allowing SomeDelegate.ValueOrDefault()(params) [the first delegate of any particular type would be cached, and used as the default for future calls].

I don't think there are necessarily a huge number of methods or classes using such constraints, but I would expect that some such classes or methods would receive very wide use if they existed.
The added value here would be to enforce that both delegate parameters are of the same type. Would you expect variance to work here? Or even that delegate void D1(); and delegate void D2(); that I can mix them on calls to those methods?
I hope ?. works with members that don't return a value, since I expect by far the number 1 usage case would be someEvent?.Invoke(params), but it not one could probably improve the convenience of delegate invocation with:
?. doesn't work on the return value of the Invoke method of the delegate but on the delegate itself.
Coordinator
Oct 8, 2014 at 2:44 PM
supercat wrote:
PauloMorgado wrote:
Given that statement, just out of curiosity, how would you use these constraints in C# (or VB)?
For enum: ...
I wonder if there are any uses of "enum" that don't involve reflection?

(and my next question: of those that do involve reflection, do any of them work with .NET Native compilation?)


-- Lucian Wischik, VB/C# language team
Oct 8, 2014 at 3:22 PM
lwischik wrote:
I wonder if there are any uses of "enum" that don't involve reflection?
There wouldn't be a whole lot of uses in code which didn't use Reflection at least once for each type, but I don't see that as a particular problem. The above code for Overlaps performs the same purpose as the HasFlag member of Enum, but does it 30 times faster and without generating temporary object instances; I don't see the fact that it uses Reflection once for each type to generate the necessary delegate as being a reason not to consider it useful. I'd rather use something like if (myFlags.Overlaps(FlagType.ThisFlag)) than if ((myFlags & FlagType.ThisFlag) != 0), but I don't want to use the hideously-slow and non-typesafe HasFlag method of Enum.

As for other uses, one could without using Reflection write a method:
bool AnyElementsInRangeHaveAnyFlags<T>(T[] arr, int start, int count, T flags) where T:System.Enum
{
  System.Enum boxedFlags = flags;
  int index=start;
  while(count> 0)
  {
    if (arr[index].HasFlag(boxedFlags))
      return true;
    index++;
    count--;
  }

  return false;
}
One could probably improve performance thirty-fold using Reflection, but the method would work, and would provide compile-time type validation of the arguments. It might be possible to achieve somewhat similar functionality without the constraint using:
bool AnyElementsHaveAnyFlags(System.Array arr, int start, int count, System.Enum flags)
{
  System.Enum boxedFlags = flags;
  IList arrAsList = arr;
  int index=start;      
  while(count> 0)
  {
    if (((System.Enum)arrAsList[index]).HasFlag(flags))
      return true;
    index++;
    count--;
  }
but that would seem a bit clunkier and wouldn't be type-safe.

To be sure, there probably aren't any cases where one would really want to use the generic constraint without using Reflection because the performance penalty for writing the "generic" method versus a type-specific one would be too great. On the other hand, Reflection really isn't that bad.

As for usability with native compilation, I would expect that code which performs myFlags.Overlaps(FlagType.SomeFlag) would probably have to call a delegate, or maybe invoke a virtual method. I would expect that the methods which are called by that delegate could be native code.
Coordinator
Oct 8, 2014 at 3:27 PM
supercat wrote:
As for usability with native compilation, I would expect that code which performs myFlags.Overlaps(FlagType.SomeFlag) would probably have to call a delegate, or maybe invoke a virtual method. I would expect that the methods which are called by that delegate could be native code.
Could you expand on that? ... Compilation of VB/C# to native is a major theme going forwards, and such code has a more difficult time with reflection and especially code generation, and I think we'd reject language features unless they played nicely with .NET Native compilation.

-- Lucian Wischik, VB/C# language team
Oct 8, 2014 at 4:15 PM
lwischik wrote:
supercat wrote:
As for usability with native compilation, I would expect that code which performs myFlags.Overlaps(FlagType.SomeFlag) would probably have to call a delegate, or maybe invoke a virtual method. I would expect that the methods which are called by that delegate could be native code.
Could you expand on that? ... Compilation of VB/C# to native is a major theme going forwards, and such code has a more difficult time with reflection and especially code generation, and I think we'd reject language features unless they played nicely with .NET Native compilation.
I've included a typical usage scenario above. I would expect that if I write:
FlagType MyFlags;
if (MyFlags.Overlaps(FlagType.Something)) ...
that would get translated into
EnumHelper.Overlaps<FlagType>(MyFlags, FlagType.Something);
which would in turn be processed as a call to static delegate
EnumHelper<MyFlags>.TestOverlapProc(MyFlags, FlagType.Something);
That delegate will point to one of nine routines, eight of which could easily be written in native code. The ninth routine, which would be the default, would use Reflection to select one of the first eight routines to associate with MyFlags and then run it.

I don't think Reflection as used here should pose a problem for native code, since its sole purpose is to select one of eight delegates. Use of a static field of a generic class to hold the delegate might be a somewhat trickier issue for native code, but it's one that code would have to be able to handle with or without reflection. It's possible (and not even difficult) for code to generate an unbounded number of distinct generic value types at runtime even without using Reflection. The only way I can see to compile to a bounded amount of machine code would be to have each method that has generic type parameters have a "real" parameter of type Type for each generic parameter, and generate code that would use Reflection to generate nested types when making nested calls. That could work, but would negate one of the big advantages of using generics in the first place.
Oct 8, 2014 at 4:37 PM
Edited Oct 8, 2014 at 5:00 PM
I have a similar suite of helper functions for both enums and delegates and I agree that said generic constraints would have been useful both in authoring them and in consuming them. However, once that itch is scratched the usefulness would likely fall off precipitously. I'd propose that these kinds of methods be proposed for inclusion in the framework so that we can share in a common implementation and then we'd have little use for changing generics.

Both constraints are legal in IL. C# has no issue consuming existing types or methods that have such constraints and will enforce them appropriately. As such including such methods in the framework is possible today, except that much of the framework is written in C# and cannot author said methods without post-processing like PostSharp.
Oct 8, 2014 at 11:22 PM
Halo_Four wrote:
I have a similar suite of helper functions for both enums and delegates and I agree that said generic constraints would have been useful both in authoring them and in consuming them. However, once that itch is scratched the usefulness would likely fall off precipitously. I'd propose that these kinds of methods be proposed for inclusion in the framework so that we can share in a common implementation and then we'd have little use for changing generics.
Given that post of the Framework is written in C#, and given that the required change to the compiler would be so minuscule, I would think that allowing the methods to be written in C# would end up taking less overall effort than hacking them into the Framework using a tool like PostSharp. Further, I generally dislike the idea of "magical" methods and types which can do things that user types cannot. I understand that there are performance reasons why some types like String have to use special support which is unavailable to user types, but I see no reason why methods which handle generic enums and delegates should need to be "special" in that way. Further, I may be overly pessimistic, but I would expect that whoever adds Framework methods to work with generic enums and delegates will probably fail to include some of the methods that I'd want.
Oct 9, 2014 at 3:17 PM
This has been a good update on the language features, but can you guys also provide an update on where you expect the tooling to be?

Specifically I'm interested in hearing if the REPL is likely to make its return by RTM of VS vNext. Also would like to hear whether the "debug lambda expressions" feature is likely to make it in.
Oct 9, 2014 at 4:57 PM
Edited Oct 9, 2014 at 4:58 PM
Halo_Four wrote:
Both constraints are legal in IL. C# has no issue consuming existing types or methods that have such constraints and will enforce them appropriately. As such including such methods in the framework is possible today, except that much of the framework is written in C# and cannot author said methods without post-processing like PostSharp.
People probably differ in what exactly they want C# to be, but I would think was intended to be to CIL what C is to assembly language. As such, anything which would be useful to express in CIL should, if practical, be expressible in C#. I doubt the creators of the C# standard saw any potential usefulness for System.Enum or System.Delegate constraints, but if it would be worthwhile for the Framework to include such constraints, that would imply that such constraints are useful.

On a more general note, I think that if a language is going to have a rule which forbids a construct which, in the absence of the rule, would have a clear and obvious meaning, the rule should at minimum offer some potential future benefit (e.g. it might forbid programmers from using constructs which could conflict with features in a future version of the language). If a rule offers no articulable benefit whatsoever, and removing it would simplify the language, and if the constructs forbidden by the rule would be unlikely to cause behavior which wasn't intended by the programmer who would write them, then I would consider the elimination of the rule to be a good thing since it would eliminate needless complexity, even if the constructs which would then be allowed were only marginally useful.
Oct 9, 2014 at 8:31 PM
supercat wrote:
Halo_Four wrote:
Both constraints are legal in IL. C# has no issue consuming existing types or methods that have such constraints and will enforce them appropriately. As such including such methods in the framework is possible today, except that much of the framework is written in C# and cannot author said methods without post-processing like PostSharp.
People probably differ in what exactly they want C# to be, but I would think was intended to be to CIL what C is to assembly language. As such, anything which would be useful to express in CIL should, if practical, be expressible in C#. I doubt the creators of the C# standard saw any potential usefulness for System.Enum or System.Delegate constraints, but if it would be worthwhile for the Framework to include such constraints, that would imply that such constraints are useful.

On a more general note, I think that if a language is going to have a rule which forbids a construct which, in the absence of the rule, would have a clear and obvious meaning, the rule should at minimum offer some potential future benefit (e.g. it might forbid programmers from using constructs which could conflict with features in a future version of the language). If a rule offers no articulable benefit whatsoever, and removing it would simplify the language, and if the constructs forbidden by the rule would be unlikely to cause behavior which wasn't intended by the programmer who would write them, then I would consider the elimination of the rule to be a good thing since it would eliminate needless complexity, even if the constructs which would then be allowed were only marginally useful.
CIL was designed to be able to do a lot more than the proposed managed languages are capable of doing, and very explicitly so. It was intended to not be bound to C#, or VB, or C++, or any other specific language, but it was designed to be able to more or less handle their requirements as appropriate. Simple example is the tail opcode, of which C# doesn't take advantage even implicitly (although the JIT tries anyway). More complex examples are support for non-IL methods which is used to embed native code. Another complex example is support for native function exports, a reverse of P/Invoke, which C# could easily support. I have the Inside IL .NET Assembler book from Serge Lidin which does a pretty good job of explaining the history and some of the design decisions but also goes pretty deep into capabilities of the framework that might surprise you.
Oct 9, 2014 at 9:17 PM
+1 for the proposed Record feature, properly, thoughtfully and expertly implemented, being preferable to the primary constructor; I like the idea but I hated the syntax.

I'm a bit sad to see declaration expressions go, but you could make it up to me with destructuring assignments. :)
Oct 9, 2014 at 9:28 PM
Looking at the feature list, there's a bunch of really good stuff already done in C# 6, particularly await in catch blocks and null propagation, so I'd just like to say two things:
  1. Good work, team!
  2. If VB gets Typecase before C# I shall throw my toys out of the pram and become one of those utter dingbats who go off to whatever the trendiest language appears to be, then writes thousands of lines of blogs posts decrying the poor fools who struggle with inferior statically-typed/object-oriented/compiled/managed languages. And I'll spell Microsoft with a $ sign, and call it Windoze, and I'll buy a top-end MacBook Air but try to run Arch Linux or Slackware on it.
Don't mess with me, because I'll do it. Probably Elixir, or Rust, or something. Or Nimrod.

Not Go, though. No generics. That's just stupid.
Oct 13, 2014 at 8:38 PM
VB currently supports "<Out()> ByRef LastErrorMessage As String" syntax for parameters but as I understand it the <Out()> is ignored. Why not as a workaround just honor the <out()> and don't issue the warning about LastErrorMessage not being initialized. In the future you can do whatever whole implementation you plan. Requiring initialization of Out parameters just makes the code confusing.
Oct 13, 2014 at 10:07 PM
paulmcohen wrote:
VB currently supports "<Out()> ByRef LastErrorMessage As String" syntax for parameters but as I understand it the <Out()> is ignored. Why not as a workaround just honor the <out()> and don't issue the warning about LastErrorMessage not being initialized. In the future you can do whatever whole implementation you plan. Requiring initialization of Out parameters just makes the code confusing.
I don't think the creators of .NET intended to have languages to do anything with Out() attributes on managed methods; the attributes were created for use with COM interop; the fact that C# decided to make them semantically significant within the language created something of an awkward situation, since code written in VB.NET can override methods which have out parameters but VB.NET regards such parameters as though they were ByRef. For VB.NET to start requiring that methods actually write to Out() parameters would be a breaking change.

Personally, I wish that even within managed code there had been distinct readonlyRef, copyOut, and copyInOut parameters in addition to in-by-value and byref. Covariance can't work with "fake" out parameters, but could work with real ones, and large structures can be passed much more efficiently as byrefs than by value. If a parameter is specified as copyOut or copyInOut, then it would be safe for a compiler to allow a property to be passed to it, even though such behavior may incorrect when passing a byref.
Oct 14, 2014 at 2:49 AM
supercat wrote:
paulmcohen wrote:
VB currently supports "<Out()> ByRef LastErrorMessage As String" syntax for parameters but as I understand it the <Out()> is ignored. Why not as a workaround just honor the <out()> and don't issue the warning about LastErrorMessage not being initialized. In the future you can do whatever whole implementation you plan. Requiring initialization of Out parameters just makes the code confusing.
I don't think the creators of .NET intended to have languages to do anything with Out() attributes on managed methods; the attributes were created for use with COM interop; the fact that C# decided to make them semantically significant within the language created something of an awkward situation, since code written in VB.NET can override methods which have out parameters but VB.NET regards such parameters as though they were ByRef. For VB.NET to start requiring that methods actually write to Out() parameters would be a breaking change.

Personally, I wish that even within managed code there had been distinct readonlyRef, copyOut, and copyInOut parameters in addition to in-by-value and byref. Covariance can't work with "fake" out parameters, but could work with real ones, and large structures can be passed much more efficiently as byrefs than by value. If a parameter is specified as copyOut or copyInOut, then it would be safe for a compiler to allow a property to be passed to it, even though such behavior may incorrect when passing a byref.
My issue is slightly different and I don't see it as a "breaking change", I just want the compiler to allow uninitialized variables to be passed in to functions that specify <Out()> without issuing a warning. it makes no logical sense to require such output variables to be initialized. Your comments are from the perspective of the called function, I am looking at it from the caller side where I think there is an issue.
Oct 14, 2014 at 3:18 PM
paulmcohen wrote:
My issue is slightly different and I don't see it as a "breaking change", I just want the compiler to allow uninitialized variables to be passed in to functions that specify <Out()> without issuing a warning. it makes no logical sense to require such output variables to be initialized. Your comments are from the perspective of the called function, I am looking at it from the caller side where I think there is an issue.
That makes sense. I suspect the reluctance to including such a feature may have stemmed from the fact that unlike in C# there would be no pretense of anything existing in the called method to ensure the value would be written. On the other hand, since there really isn't any mechanism to ensure the called method will write the value, having it eliminate the warning would be no worse than having it satisfy the requirement that the variable be considered written.

Actually, what might have been nice would have been to allow code to pass an out argument to a method with a ref parameter, with the semantics that given void someMethod(ref Thing it);, a call someMethod(out foo); would be shorthand for foo = default(Thing); someMethod(ref foo);. Had things been implemented that way, the semantics of TryGetValue() methods could have been improved by having them use ref parameters (rather than out) and specifying that a failure which doesn't cause an exception will leave the passed-in value unchanged, thus allowing:
var myValue;
if (!Collection.TryGetValue(whatever, out myValue))
  myValue = desiredDefault;
to be replaced with
var myValue = desiredDefault;
TryGetValue(whatever, ref myValue);
Too late now to do that with existing interfaces, though.
Oct 15, 2014 at 4:36 AM
My use case is very different. I want to use the "Out" value to propagate detailed messages to the user in the case of a failure. if the function succeeds no one will ever see the message and I don't need a default value.
Oct 17, 2014 at 7:32 PM
sorry to be the guy who has to ask... could someone explain or post links to the "record" and "pattern matching" features that are discussed here? I thought I had seen a lot in terms of computer languages, but i'm not finding anything that explains these in terms of language design.

thanks
Oct 17, 2014 at 9:19 PM
burton wrote:
sorry to be the guy who has to ask... could someone explain or post links to the "record" and "pattern matching" features that are discussed here? I thought I had seen a lot in terms of computer languages, but i'm not finding anything that explains these in terms of language design.

thanks
Check out this discussion which links to a Word doc. This is a proposal for a potential future feature of the language, something similar to what is found commonly in functional languages.

Draft spec for records and pattern-matching in C#
Dec 12, 2014 at 5:37 PM
I'm happy now too.
May 5, 2015 at 4:06 PM
D'aww, I was writing something like this:
fooSequence = fooSequence.Where(foo => { int parsedBar; return Int32.TryParse(foo.BarString, out parsedBar) && parsedBar < someThreshold; });
and came across this post when I was looking to see if this would be legal C# 6 to get rid of the curly braces without moving the variable out and creating a closure that's incorrect when fooSequence is, e.g., a ParallelQuery:
fooSequence = fooSequence.Where(foo => Int32.TryParse(foo.BarString, out int parsedBar) && parsedBar < someThreshold);
Anyway, not the end of the world. Just wanted to chime in my support for declaration expressions by pointing out a construct that you've probably seen before.
May 5, 2015 at 4:16 PM
Just to note, Roslyn has been moved to GitHub and all conversations now take place here.

I don't think that declaration expressions have been revisited since being dropped from C# 6.0. Possibly the scoping issues were too problematic.