# C# Language Design Meeting for December 4th, 2023

## Agenda

- [Lock statement pattern](#lock-statement-pattern)
- [`BinaryCompatOnlyAttribute`](#binarycompatonlyattribute)

## Quote(s) of the Day

- "New syntax?" "`lock(ness) // monster`"
- "Protect against Murphy, not Machiavelli."

## Discussion

### Lock statement pattern

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

We started today by looking at an update for locking in .NET. .NET 9 is looking at adding a new locking primitive, `System.Threading.Lock`, and we need to
decide what, if anything, the language needs to do to react to this change. There are three main points of contention here:

1. Should we do anything at all?
2. If we do, do we try to protect against accidentally observing the wrong behavior?
3. Do we support a general pattern here, or just one specific type?

To the first question, there is some question as to whether we're ok with adding a new behavior for the `lock` keyword. For users of C#, does `lock` specifically
mean `Monitor.Enter()`, as it has for the entire lifetime of C#, or does it have a broader meaning? There are certainly other types of locks in the BCL that do
not do anything special with `lock` today; for example, `System.Threading.SpinLock` will not actually do a spin lock if `lock (spinLockInstance)` is done, but
will just call `Monitor.Enter()`. This may confuse some users, but it's worked this way since the type was introduced (.NET 4.0). Is `System.Threading.Lock`
special enough that it needs separate handling? After some discussion, we think the answer is not only yes, we think it's unfortunate that `SpinLock` doesn't do
similar. Instead of "`lock` calls a specific API", we think the general user intuition is "`lock` enters a mutual exclusion zone and helps keep me safe from races",
which is a much broader intuition. We also think it would be generally unfortunate if the advice we give to users is "Don't use the built-in `Lock` type with the
`lock` keyword."

Next, we looked at the immediate concerns brought up by 1: what about times when the lock is observed as an `object`, rather than as a `Lock`? The compiler cannot
handle this case in codegen, so the options for dealing with it are having the runtime handle it in `Monitor.Enter()` somehow, or performing some static analysis to
try and warn/error about when `Lock` is upcast to `object`. Having the runtime magically handle it is attractive from a language design standpoint, but unfortunately
not realistic from an implementation standpoint, particularly not unless we want to penalize all the existing locking code in .NET. Therefore, we turned to looking
at static analysis. One thing that comes to the top of mind here is that, while there are lots of fun corner cases (unconstrained generics, for example), most of
these corners aren't likely anything that a user will actually do with a `Lock`. The use pattern for these types of objects is to simply store them as a class field
and `lock(this.lock)` where necessary. Locks usually don't get passed around through generics or other such areas, as that generally violates encapsulation. So the
number of bugs that errors for upcasting will prevent are likely small. That being said, we don't think we should just brush this potential risk off as being not
realistic either. Instead, we think that the compiler should perform some amount of static analysis, and warn where possible; this will catch most potential issues,
but leave an escape hatch for when users really want to do something more clever.

Finally, we thought about generalizations. As mentioned earlier, we think it's unfortunate types like `SpinLock` aren't able to participate in `lock` as might be
expected. That being said, we don't particularly like the pattern-based approach this proposal is taking. This is something that could be an interface with a type
parameter, except for the fact that the `Scope` type is a `ref struct` and cannot go in an interface. Given that we are investigating allowing `ref struct`s into
generics, and that the runtime doesn't plan on changing anything but `System.Threading.Lock` for C# 13/.NET 9, we think we should just special case the new type for
now, and look at a broader pattern later when we have more use cases.

#### Conclusion

We generally accept the changes for special casing how `System.Threading.Lock` interacts with the `lock` keyword, but we will not adopt the full pattern at this time.
We will look at static analysis warnings to help make sure that accidental missuse of the type does not occur.

### `BinaryCompatOnlyAttribute`

https://github.com/dotnet/csharplang/issues/7706  
https://github.com/dotnet/csharplang/pull/7707

Finally today, we took a (very) brief look at this proposal. There was strong support from LDM for a general feature, and the BCL also would make heavy usage of this
if it was added. There are still plenty of open questions to be answered (and indeed, we need to answer if this is quite the right feature, or if the feature we really
want is a knob to control overload resolution at a finer grain), but we think we should take those questions on in the near term.

#### Conclusion

Feature moves into the working set.
