# C# Language Design Meeting for November 12th, 2025

## Agenda

- [Unsafe evolution](#unsafe-evolution)

## Quote of the Day

- "Did you just say Romulan?" "No, I said cromulent."

## Discussion

### Unsafe evolution

Champion issue: https://github.com/dotnet/csharplang/issues/9704  
Specification: https://github.com/dotnet/csharplang/blob/4c6bee6ceaa48dc64a42f25d6a50155e1def2930/proposals/unsafe-evolution.md  
Related: https://github.com/dotnet/designs/blob/2b9e1b311d16ea142b4047d6eddeef15979ba6de/proposed/caller-unsafe.md

Today, we [continued](./LDM-2025-11-05.md#unsafe-evolution) talking about the future of `unsafe` in C#. Our main focus today was on how members
are declared as requiring an `unsafe` context: do we repurpose the `unsafe` keyword on members to mean this? Or do we do something new, such as
a new keyword or having an attribute to indicate this? After some discussion, we do believe that `unsafe` conveys what we want here. Much like
nullable reference types, the future we want to get to isn't with the `unsafe` keyword as this odd vestigial thing, we want the feature to feel
unified. Given that we feel pretty confident that we want to repurpose `unsafe` on members, even if that means increasing the scope of the
breaking change in the language.

Next, we considered the broader application of `unsafe` on types. The new rules are very explicit that types cannot be considered `unsafe` by
nature: it is only specific types of memory accesses that are `unsafe`. We therefore have a few options for what to do:

1. Automatically mark all members inside an `unsafe` type as `unsafe`. This is the current proposal.
2. Keep the historical meaning of `unsafe`: the body of the type is in an `unsafe` context, but members will still need a separate `unsafe`
   modifier to be considered `unsafe` to call.
3. Disallow `unsafe` on types.
4. Allow `unsafe` as a modifier on types, but remove all meaning. Produce a warning that it is vestigial.

All of these are fairly large changes in one way or another; a simple search across GitHub indicates at least 150K results for `unsafe class`
or `unsafe struct`, excluding forked projects. A decent number of spot checks of these have shown that they're not actually `unsafe`; the
developer simply marked the type as `unsafe` even though no pointers or `unsafe` memory accesses occurred in the type. There are plenty of real
`unsafe` spots, though, so unless we were to adopt option 2, it would be a large breaking change.

Looking more at options 1 and 2 though, we're not actually convinced that these truly help bring down the magnitude of the breaking change. In
either case, developers really do still need to adjust their members. Option 1 will bleed `unsafe` out into the rest of the code, and both
options 1 and 2 make the scope of the `unsafe` blocks far too broad. In both cases, we don't actually _want_ users to put `unsafe` on their types.
It implies that a type can be `unsafe`, which is not how the feature works. We are then left with options 3 and 4, where 4 is just 3 but without
a hard error. There's definitely appetite for fully prohibiting `unsafe` on types altogether, but we're hesitant to fully commit at this time.
We'll proceed with option 4 for now, and come back to the question of 3 vs 4 in a few weeks after we've had some time to think more about it.

Another area we considered is whether or not `unsafe` as a modifier on a member should make the entire body of that member an `unsafe` context.
Rust did this originally, and has since moved to requiring an explicit `unsafe` block, even for a member marked as `unsafe`. This helps call out
the specific unsafety, rather than saying "this entire 100 line method is unsafe, good luck finding the actual bit of concern". We don't have
conclusions on this today, but will add it to our list of questions to resolve.

#### Conclusion

We will use `unsafe` on members as the way to denote that calling a member must be performed in an `unsafe` context. `unsafe` on a type will have
no meaning, and we will revisit the question of whether to outright disallow it, or just add a warning.
