# C# Language Design Meeting for October 26st, 2020

## Agenda

1. [Pointer types in records](#pointer-types-in-records)
2. [Triage](#triage)
    1. [readonly classes and records](#readonly-classes-and-records)
    2. [Target typed anonymous type initializers](#target-typed-anonymous-type-initializers)
    3. [Static local functions in base calls](#static-local-functions-in-base-calls)

## Quote of the Day

- "And I specialize in taking facetious questions and answering them literally"

## Discussion

### Pointer types in records

Today, you cannot use pointer types in records, because our lowering will use `EqualityComparer<T>.Default`, and pointer
types are not allowed as generic type arguments in general. We could specially recognize pointer types here, and use a
different equality when comparing fields of that type. We have a similar issue with anonymous types, where pointers are
not permitted for the same reason (and indeed, Roslyn's code for generating the equality implementation is shared between
these constructs). We would also need consider every place record types can be used if we enabled this: for example, what
would the experience be when attempting to pattern deconstruct on a record type, as pointer types are not allowed in patterns
today? It also might not be a good idea to introduce value equality based on pointer types to class types, as this is not
well-defined for all pointer types (function pointers, for example). Finally, the runtime has talked several times about
enabling pointer types as generic type parameters, and if they were to do so then the rules for this might fall out at that
time.

#### Conclusion

Triaged to the Backlog. We're not convinced this needs to be something that we enable right now, and may end up being resolved
by fallout from other changes.

### Triage

#### readonly classes and records

https://github.com/dotnet/csharplang/issues/3885

This proposal would allow marking a class type `readonly`, ensuring that all fields and properties on the type must be `readonly`
as well. Several familiar questions were immediately raised, namely around the benefit. `readonly` has a very specific benefit
for struct types, around allowing the compiler to avoid defensive copies where they would otherwise be necessary. For
`readonly` classes, there is no clear similar advantage. We might not even emit such information to metadata, and the main
benefit would be for type authors, not for type consumers. There is also some concern about whether this would be confusing to
users, particularly if this does not apply to an entire hierarchy. If you depend on a non-Object base type that has mutable,
then the benefits of using `readonly` are not as clear, even for a type author. Similarly, if a non-`readonly` type can inherit
from a `readonly` type, that means that any guarantees on the current type aren't very strong, as mutation can occur under the
hood anyway. `readonly` in C# today always means shallow immutability, so there is an argument to be made that this level of
hierarchy-mutability is not too different.  
We also looked at the question of whether this feature should just be analyzer. There is certainly argument for that: particularly
if there is no hierarchy impact, it seems a perfect use case for an analyzer. However, this is a case where we allow the keyword
on one set of types, while not allowing it on a different set of types. Further, unlike many such proposals, we already have a
C# keyword that is perfect for the scenario.

##### Conclusion

Triaged into the Working Set. We'll look at this with low priority, and particularly try to see what the scenarios around
hierarchical enforcement look like, as those were more generally palatable to LDT members.

#### Target typed anonymous type initializers

https://github.com/dotnet/csharplang/issues/3957

This is a proposal to address some cognitive dissonance we have with object creation in C#: you can leave off the parens if you
have an object initializer, but only if you specify the type. While it does save 2 characters, that is not a primary motivation
of this proposal. There are grow-up stories for other areas we could explore in this space as well: we could allow F#-style
object expressions, for example, or borrow from Java and allow anonymous types to actually inherit from existing types/interfaces.
However, we have a number of concerns about the compat aspects of doing this, where adding a new `object` overload can silently
change consumer code to call a different overload and create an anonymous type. In these types of scenarios, it might even be
impossible to determine if the user made an error: if they typed a wrong letter in the property name, for example, we might be
forced to create an anonymous type silently, instead of erroring on the invalid object initializer.

We also briefly considered more radical changes to the syntax: for example, could we allow TS/JS-style object creation, with
just the brackets? However, this idea was not very well received by the LDM.

##### Conclusion

Triaged into the Backlog. While we're open to new proposals in this space that significantly shift the bar (such as around new
ways of creating anonymous types that inherit from existing types), we think that this proposal could end up conflicting with
any such future proposals and should be considered then.

#### Static local functions in base calls

https://github.com/dotnet/csharplang/issues/3980

This is a proposal that, depending on the exact specification, would either be a breaking change or have complicated lookup rules
designed to avoid the breaking change. It also requires some deep thought into how the exact scoping rules would work. Today,
locals introduced in the `base` call are visible throughout the constructor, so we would have to retcon the scoping rules to
work something like this:

1. Outermost scope, contains static local functions
2. Middle scope, contains the base clause and any variables declared there
3. Inner scope, contains the method body locals and regular local functions.

This also raises the question of whether we should stop here. For example, it might be nice if `const` locals could be used as
parameter default values, or if attributes could use names from inside a method body. We've had a few proposals for creating
various parts of a "method header" scope (such as https://github.com/dotnet/csharplang/issues/373), we could consider extending
that generally to allow this type of thing. Another question would be: why stop at `static` local functions? We could allow
regular local functions in the base clause, and leverage definite assignment to continue doing the same things it does today to
make sure that things aren't used before assignment. This might work well with a general "method header" scope, instead of the
scheme proposed above. Finally, we considered simply allowing the `base` call to be done in the body of the constructor instead,
a la Visual Basic. This has some support, and would allow us to avoid the question of a method header scope by simply allowing
users to move the base call to where the local function is visible.

##### Conclusion

Triaged into the Working Set. We like the idea, and have a few avenues to explore around method header scopes or allowing the
base call to be moved.
