Please log in to watch this conference skillscast.
As you were looking the other way, C# became a cross-platform, open-source, high-performance, general-purpose, hyphenated-buzzword programming language. It is also very popular! I’ll take you on a journey of language design nerdery, targeted equally at C# newbies and oldies. Let’s see how some of our recent features take on the null menace, immutability, and value semantics in the context of object-oriented programming, and peek at some of the next ideas we’re tinkering with.
Q&A
Question: About 6(!) C# versions ago, Anders Hejlsberg swatted down the idea of AOP in C#, and now with Source Generators, even if the code generated is immutable, isn't this dipping into C# metaprogramming in itself? And if developers are going to be allowed to hook new extensions into the C# compiler such as Source Generators, why not do the Full Monty (TM) and open the compiler up for more extensions from the community?
Answer: I get what you're saying, but we really like the separation between programming and metaprogramming. With source generators we think that we got that to a pretty elegant place! To make sure that generated source fits in well with manually written source, we have somewhat extended the "partial methods" feature to better merge ("weave" ;-)) things together.
Question: I assume you can nest records, and if so is it still good comparing parent records?
Answer: You can definitely nest them! Equality on the top record just calls whatever equality is on its nested objects, so if they are also records it will be recursive.
Question: Do C# records have “Copy on write”, like Swift?
Answer: Not really. When you do a "with" expression you immediately get a copy, and any changes in the object initializer immediately applied. Unless you cheated and made the record mutable (which you can), you will have no more changes after that point.
So in a sense, you have the copy and the write immediately!
Question: I was thinking of a deeply nested record structure. If you change one of the properties of the “parent” object (using a “with”), do all of it’s member records get copied too, even if they are not changed?
eg:
record Name(String first, String last) record Person(Name name, Int age) x = Person(Name("Dominic", "Godwin"), 21) // Not really 21 :slightlysmilingface: y = x with { age = 22} // (sorry can't remember the exact syntax
Does person.name get copied or does it point to the same object?
Answer: The copy is shallow. It is closely modelled over the copy that happens when a struct is assigned; i.e. reference types are copied by reference, value types by value.
We're thinking about allowing nested non-destructive mutation, but that didn't make it into C# 9.0
Question: Also, is there any point to c# structs, now we have records?
Answer: Structs and records have the same equality semantics, and the copy that happens in a with-expression on records is the same that happens on structs by any assignment.
Structs don't require heap allocation, so they have very different runtime, performance and memory properties.
Question: Anything interesting to consider with using records for EF Core/JSON serializers etc?
Answer: The tricks that allow deserialization into even immutable data models (with readonly fields inside) still work.
The ORM aspect of EF, tracking the state of mutable objects, that really works better with a mutable object model!
Question: Are there any plans to add extension properties?
Answer: Yes. They would come in as part of the extensions I showed in the last part of the talk,
Question: Any plans of adding the javascript spread operator into c#?
Answer: Not currently. Should we?
Question: Here is a small example using javascript syntax.
Wasn’t sure if you could add this sort of syntactic sugar to the c# records?
const person = { firstName: 'Gary', lastName: 'Butler' }; const modifiedPerson = {...person, middleName: 'Fred'}; // Add middleName const anotherModifiedPerson = {...modifiedPerson, middleName: 'John'}; // Replace middleName const copyOfPerson = {...person}; console.log(anotherModifiedPerson);
Answer: Got it! The interesting trait here is that this use of the spread operator actually creates new types (with more members), and then copies existing values in. This is a great fit for a structural type system like TypeScript's, but kind of grates against a nominal type system like what C# has today.
That said, we have been talking about data transformation scenarios, where record-like data moves through filters and projections. We already have something like that in LINQ (language integrated queries), where we introduced anonymous types to represent "shapes" that are ephemeral and don't need a type name. Those are quite limited today, and can't cross assembly ("module") boundaries, but we are wondering if it's time to generalize things here. Ways of creating shapes from other shapes (such as the spread operator) could be handy there - thanks for bringing that up!
Question: Do Roles == Shapes?
Answer: Roles are an evolution of Shapes, if you look at the GitHub issues on them. Exploration: Roles, extension interfaces and static interface members · Issue #1711 · dotnet/csharplang (github.com)
Question: Does C# have higher-kinded types yet?
Answer: No. It's not super high on our priority list.
Question: Is there any sort of sugar to make it easier to access an IMonoid
that's exported by some library and also access the IntMonoid
role at the same time (assuming the library has exported both the interface and the implementations of it for some common types)? Or is the solution just to import both
Answer: That's a level of design details we haven't gotten to yet. If you look at current extension methods, they are brought in with using
directives, and I could imagine bringing in a namespace that has both the interface and its extensions for well known types in one fell swoop.
Question: You spoke at the end about extending/modifying the .NET runtime to be able to support new language features, to what extent is F# involved in this - are we likely to see any language improvements enabled by new runtime capabilities?
Answer: We talk to the F# team regularly, and we always think about how to cross-pollinate the features, especially when they affect metadata or runtime. Same goes for VB.
YOU MAY ALSO LIKE:
Tune in to C#
Mads Torgersen
Mads Torgersen is the language PM for C# at Microsoft, where he runs the C# language design process and maintains the language specification. He is also on the design team for TypeScript and Visual Basic, and he contributes to the Roslyn project, which has reinvented the C# and VB compilers and taken them open source.
Many years ago Mads was a professor, and also contributed to a language starting with J.