
# C# Language Design for March 9, 2020

## Agenda

1. Design review
2. Records

## Discussion

### Simple Programs

In the design review we covered the "simple programs" feature. A big piece of feedback is that
they didn't like the "middle ground" we had carved out with local functions. Right now we have
local functions that can exist both in the top-level statement "file" and also across other
files. Because the design allows only local functions at the top level, those functions are only
accessible from and can only access the statements in the "top-level statement file."

The feedback was that this would be an unfortunate design point. Organizing local functions in
other files, when they can't be accessed by other files, is a big problem. There are two places
we could go with this. We could either pull back and allow many of these forms only in the
"top-level statement file." Or we could go the other way and allow more functionality at the top
level, like allowing truly top-level members, including functions and variables, that can be
declared and referenced from everything in the program.

Allowing full top-level members is attractive but opens a lot of questions. The most important is
top-level variables. By allowing top-level variables and giving them the C# default of
mutability, we would effectively be enabling mutable global variables. There is collective
agreement that in everything but the smallest programs this is a bad programming practice and we
shouldn't encourage it.

We could try to pivot on syntactic differences. One major difference between local variables and
functions and member-level variables and functions is that members allow accessibility modifiers.
Top-level statements could be, by default, local variables. Accessibility modifiers, `public`,
`private`, `internal`, et al., could differentiate between top-level and local variables.
However, this feels like it may be too subtle a design point, relying too much on minor syntactic
decisions to decide things like scoping.

The biggest takeaway is that this is a complex topic with a lot possibilities. Maybe we could try
to carve out a small portion to make some progress, without committing to a narrow design for the
entire space of "top-level members." We generally like this approach, but CSX makes things
difficult. Since the existing design focuses on local variables and local functions,
compatibility with any sort of submission system is a problem. Fundamentally, we would need to
decide which pieces of state in a C# program are "transient," in that they cannot be referenced
from a new submission, and which are "preserved."

The value still seems important enough to move forward. There's general agreement that top-level
statements are useful. Some people think they are useful in the simple form already presented,
while other people want to see this as the starting point for a full feature, and these views are
roughly compatible.

If we move forward with our subset, we need to flesh out the mental model for how it works.
Specifically, it's important to note why top-level variables and functions would be inaccessible
from inside classes. One way to think about this is the difference between instance and static.
When you're in a static context, all the instance variables are visible, but not accessible. You
could also model it as the statements are directly inserted into Main (which is true).

**Conclusion**

We'd like to move forward with the prototype with the modification that top-level statements can
only appear in one file. Symbols declared in these statements would be visible, but an error to
access inside classes. All the top-level statements are treated as if they were inside an async
Main method.

### Value equality

When we discussed records in the design meeting we brought up value equality for records and a
proposal for extending to regular classes. A big shift was that records should have an easy
global automatic value equality, while general classes should never have a global opt-in.

This seems contradictory, but if records have a set of default semantics that naturally fit value
equality, then having it enabled by default is suitable. Value equality plays particularly well
with immutability. Since records strongly support immutable programming, supporting value
equality is natural. For arbitrary classes, however, it's not clear at all how value equality
should behave. Opt-ing in either all or only some members seems to have downsides for many class
examples.

We're not ruling out value equality for regular classes, but for the future we'd like to examine
specifically how we'd like value equality to work for records. This could impact how and when we
bring generated value equality to conventional user classes.