# C# Language Design Meeting for February 1st, 2023

## Agenda

- [Position of `unsafe` in aliases](#position-of-unsafe-in-aliases)
- [Roles and extensions](#roles-and-extensions)

## Discussion

### Position of `unsafe` in aliases

https://github.com/dotnet/csharplang/blob/main/proposals/using-alias-types.md#supporting-aliases-to-types-containing-pointers

As part of allowing pointer types in using aliases, we want to enable aliases to carry the `unsafe` keyword. But where should it go - before or after the `using` keyword?

Today, one modifier appears *before* the `using` keyword (`global`), and one appears after (`static`). Looking at these, `global` affects *where* the using takes effect, and applies to all forms of using directives. Conversely, `static` applies only to one form of using directive, and only has meaning for that one. It seems that `unsafe` aligns more with the second category, as it only applies to using *aliases*.

Additionally, it is useful for all `using`s (and `global using`s respectively) to align visually with the operative keyword(s) in the same horizontal position.

#### Conclusion

Go with `using unsafe` rather than `unsafe using`.

### Roles and extensions

https://github.com/dotnet/csharplang/pull/6880

We reviewed the roles and extension proposal in its current state to provide feedback to the working group. The below sections contains points for clarification and open questions for the group to pursue.

#### Terminology

We are not necessarily in love with the term "role", and may well change it. It could e.g. be "view". However we'll save that discussion for later.

#### Phases

The proposal operates with three phases:

- "A" provides only static extension members (static methods, properties, fields, etc.)
- "B" provides extensions and roles, allowing them to add all static and instance members, except for instance fields, auto-properties or field-like events. Constructors are also an open question.
- "C" allows extensions and roles to implement interfaces

The phase A vs B split is not just there for potential sequencing over multiple releases: the phase A scenarios have potential for more downlevel friendly code gen, since they do not need to represent an underlying value. Even if we ship phase A and B at the same time, it may be worth ensuring that "static only" scenarios are more easily targeted to older runtimes.

#### Syntax

The proposed syntax allows for multiple base roles, establishing an inheritance hierarchy among roles.

Type members can't be virtual (no virtual, abstract or override modifiers), because the underlying values exist independently of the roles, and therefore cannot have their behavior modified by role declarations.

Roles can be nested in roles.

Should there be prefix naming conventions for roles and extensions (e.g. `RCustomer`, `EOrder` - or `XOrder`?), like there are for interfaces and type parameters (`ICustomer`, `TOrder`)?

#### Underlying type

The proposal doesn't use "inheritance" to describe the relationship to the underlying type, even though members are "inherited" in the sense that they are available on the role as well. This is so that we can distinguish where e.g. protected doesn't apply, and to emphasize that roles can augment even sealed types and structs. We need clear differentiating terminology, but this may or may not be the right one.

Some of the listed restrictions on underlying types are likely temporary, and imposed by envisioned emit strategy (pointers, ref structs). Others are likely permanent (dynamic, nullable reference type). The doc should clarify that.

The rule about extension type parameters all being used by the underlying type is so that we can infer backwards when searching for extensions. We have similar needs for extension methods today.

#### Conversions

There is an identity conversion between a role and its underlying type, as well as its base roles. The current proposal does not allow sideways identity conversion between roles with the same underlying type, which would mean identity conversion isn't transitive (unlike in the existing language). If this is a problem, we may consider always allowing identity conversion when the underlying type matches, but perhaps give a warning on sideways conversion to preserve some "type safety" across role hierarchies.

Does the identity conversion thing clash with the ability to overload methods on role parameter types? Not necessarily. Betterness has an "exact match" clause that would allow you to distinguish. It's desirable to have overload resolution on roles, and we hope it's possible from a metadata perspective, but that remains to be investigated.

#### How is an extension "activated"

Whoever declares an extension decides that it is an extension. Whenever it is in scope or imported with a `using` directive, the extension applies to its underlying type. This is equivalent to how extension methods work today. Another design would be to have just one kind of declaration, and have the user decide whether to apply the role as an extension. We tentatively agree that whoever declares an extension knows that it is going to be used as an extension, and designs it for that purpose. Also this is less of a deviation from today's behavior.

#### Type tests

Will you be able to tell roles apart with pattern matching? No, from a runtime perspective they represent the same underlying type, which is the thing we can check for at runtime.

#### Why are extensions named types?

Why do we think extension types are important? Mostly disambiguation. You can explicitly convert from an underlying type to the extension, and now the extension's members go to the foreground, hiding other extensions. 

This also underscores the close relationship between extensions and roles. Extensions are essentially roles that get automatically applied.

If/when we get to phase "C", this becomes more important, as an extension can implement additional interfaces on behalf of its underlying type, and therefore needs to be able to be passed as a type argument for type parameters constrained by such interfaces. Therefore it needs to be a type.

#### Types and roles

The type of `this` within a role's instance members is the role type itself.

A role satisfies the same constraints as the underlying type. That means value vs reference type (`struct` vs `class` constraint) depends on the underlying type, not the role itself.

#### Interaction with extension methods

Old-fashioned extension methods will have some restrictions in their interaction with roles and extensions. This is TBD.

#### Member lookup

Today you cannot call an extension method with a simple name, even if you're inside of the extended type. We're planning to keep that restriction: The lookup would get weirdly two-dimensional and it doesn't seem worth the trouble or potential surprises.

Member lookup on a role goes to the role, then base roles, *then* the underlying type.

Member lookup (on all types) is also augmented so that if we don't find anything, we'll look in compatible extensions.

Extension member lookup is a generalization of today's extension method lookup, except that we can look for other kinds of members, and that we can look at enclosing types.

#### Scenarios

Previous documents on roles describe several scenarios in more detail. It would be good to gather those (and more) scenarios, and evolve them with the proposal.

Examples would also help make it a bit easier to follow the behaviors and restrictions. 

#### Conclusion

With the above feedback in mind, the working group is encouraged to continue fleshing out the proposal.
