# C# Language Design Meeting for April 6th, 2026

## Agenda

- [Unsafe evolution, continued](#unsafe-evolution-continued)
    - [Simple core model](#simple-core-model)
    - [`extern` members and explicit safety markers](#extern-members-and-explicit-safety-markers)

## Quote(s) of the Day

- "None of us is as pedantic as all of us"
- "I'm feeling unsafe"
- "Congratulations to the Integrity crew on breaking the record for distance traveled by a human from the Earth, which occurred during this LDM"

## Discussion

### Unsafe evolution, continued

Champion issue: https://github.com/dotnet/csharplang/issues/9704  
Spec: https://github.com/dotnet/csharplang/blob/50484a8eb9d0d142e2496b52dcc40ced9639ea7a/proposals/unsafe-evolution.md  
Working group notes: https://github.com/dotnet/csharplang/blob/50484a8eb9d0d142e2496b52dcc40ced9639ea7a/meetings/working-groups/unsafe-evolution/unsafe-simple-core-model.md

Continuing from [last week's discussion](./LDM-2026-04-01.md#unsafe-evolution-migration-and-explicit-safety-markers),
we focused on a deliberately simplified proposal for unsafe evolution. The feature space still feels tightly constrained,
and we acknowledged that any viable direction is likely to require trade-offs from everyone. The aim for today was not
to resolve every outstanding edge case, but to decide whether there is a simple core we can build on and then refine
with separate follow-on decisions.

#### Simple core model

The proposed core model is intentionally minimal. Opt-in is assembly-wide and binary. In an opted-in assembly,
`unsafe` continues to establish an unsafe context as it does today, but when placed on a member it also means that the
member is caller-unsafe. At the same time, most pointer operations become safe regardless of opt-in, with only
operations that actually dereference or otherwise directly access pointed-to memory still requiring an unsafe context.

A central point in favor of this approach is that it expands the meaning of `unsafe` rather than replacing it with a
separate concept. We view `unsafe` on a body as localizing the audit obligation to that body, while `unsafe` on a
signature extends that obligation to the caller. That framing helps make the proposal feel like a consistent evolution
of the language instead of an arbitrary repurposing of an existing keyword.

We also spent time on the migration story. Because pointer declarations and most pointer manipulations become safe
independently of opt-in, users can reshape existing code before they flip the switch: moving `unsafe` inward when the
member handles the risk internally, or outward when the caller truly must participate in the audit. We think this is
particularly valuable for multi-targeting scenarios and for generated code, where an incremental path is important.

Several known complications are explicitly left out of the core model and treated as optional add-ons for later
discussion. These include finer-grained opt-in, staged adoption, the treatment of members with pointer-containing
signatures, and whether opted-in code should support narrower audit scopes inside already-unsafe members. We are
comfortable deferring those details to follow-up meetings if we agree on the base proposal in the coming weeks.

#### `extern` members and explicit safety markers

The most significant unresolved concern was interop. `extern` and similar library import members are very often
caller-unsafe, yet under the simplest form of the proposal they remain silently safe unless explicitly marked. That felt
too risky, not just during migration but also for future maintenance, where newly added interop declarations should
force an intentional safety decision rather than compiling quietly by default.

We discussed two main ways of addressing this. One is to flip the default for these members and require an explicit
marker only for the small number that are actually caller-safe. The other, which drew strong support, is to keep the
general model but require every such member to be explicitly annotated as either `safe` or `unsafe`. That preserves the
regularity and searchability of `unsafe` while still forcing an explicit audit at one of the highest-risk boundaries.

There was still some uncertainty about the exact mechanics, especially around migration and metadata, but that did not
change the overall direction of the conversation. The room generally agreed that this was a question of how to expose
and enforce the model, not a reason to abandon the model itself.

#### Conclusion

We will move forward with the general shape of the simple core model for unsafe evolution, and will continue to nail
down the specific remaining pieces in future meetings.

For `extern` and similar interop members, we are heavily leaning toward requiring an explicit annotation that the member
is either `safe` or `unsafe`, with the exact syntax for the `safe` side still to be determined. We will revisit this
approach during our next discussion, where we will also consider similar questions for other categories of members, such
as methods with pointer parameters.
