meetings/2023/LDM-2023-02-01.md
unsafe in aliasesAs 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 usings (and global usings respectively) to align visually with the operative keyword(s) in the same horizontal position.
Go with using unsafe rather than unsafe using.
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.
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.
The proposal operates with three phases:
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.
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)?
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.
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.
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.
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 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.
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.
Old-fashioned extension methods will have some restrictions in their interaction with roles and extensions. This is TBD.
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.
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.
With the above feedback in mind, the working group is encouraged to continue fleshing out the proposal.