80 lines
No EOL
4.7 KiB
Markdown
80 lines
No EOL
4.7 KiB
Markdown
|
|
# 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. |