# Roles WG 2023-01-23

Earlier this week, we reviewed the proposed lookup rules. 
We're continuing to review https://github.com/jcouv/csharplang/blob/roles-spec/proposals/roles.md

## Static-ness

Roles must support a non-static flavor and since any role can be turned into an extension,
extensions must also support a non-static flavor.  
But it doesn't make sense to allow a non-static extension on a static underlying type.  

The proposal we're landing on is that roles/extensions would not require specifying 
static-ness. We would use the static-ness from the underlying type and disallow 
explicit `static` modifiers.

This approach seems convenient for users. But allowing a `static` modifier could be useful
to avoid emitting a ref field when possible. Some auto-detection might also be possible, but
not very attractive.

## Is it necessary to place the nesting restriction?

Let's remove the restriction. We can update the extension member lookup rules to first look in 
enclosing types then enclosing namespaces.  
Treating types as scopes like namespaces invites allowing usings/imports in types, but let's not.  



## Static imports

Is it a general principle that an extension is in effect when its type can be accessed with a simple name? 
If so, can a static using of an enclosing type bring a nested extension in effect?

Should `using static C;` bring the nested extension into scope?  

```
public class C
{
    public extension E 
    { 
    }
}

using static C;
// E an extension here?
```

Yes, this would make sense. You could name the type `E` from that location,
so the extension members should be in scope.

## Modifiers

Since we're allowing nested roles/extensions, then we'll allow the `private` modifier.  
We should allow the `file` modifier.

## Underlying type

### Pointer

Should we disallow pointer types as underlying types?  
There is precedent with extension methods and some issues with metadata (`System.Role<pointer>`).  
On the other hand, it would be nice to support.  
We'll start by disallowing pointer types, but let's find an emit strategy that would allow them eventually.  

### Nullability

Just like for base types, we'll disallow top-level nullability in underlying types.
Nested nullability should be allowed, but it will not affect lookup.  
We may want to warn on mismatch on nullability when used.  

### Ref structs

We would like to allow ref structs as underlying type for roles/extension, but 
our emit strategy relies on ref fields, which don't yet support ref structs.  
Maybe the lifetime rules could allow this, given that the usage pattern is controlled/limited.  

### Roles

We would like to allow role types as underlying types.
Maybe we should even allow **multiple role types** in the definition of a role.  

```
role DiamondRole : NarrowerUnderlyingType, BaseRole1, Interface1, BaseRole2, Interface2 { }
```

The relationship between a role and it's "base role" would not be one of inheritance and virtual calls:
```cs
class C
{
    void M() { ... }
}
role R1 : C
{
    // New version adds below
    //void M() { ... }
}

// Different library
role R2 : R1
{
    void M2()
    {
        M();
    }
}
```

We still need to refine terminology.  
Since members of a role shadow its underlying type, maybe we should emit a warning when shadowing a name? (need to add `new`)

### Extensions
Extensions are just roles, and roles are allowed in underlying role list. So extensions should be allowed too.

### Extension syntax

The current syntax proposal puts the producer of a role in charge of making it
an extension or not. Should we use a syntax that puts the consumer in charge instead?  
```
role R { }
using R;
```
`extension role R`?
`extension E : R;`?

### What kind of type are roles/extensions?

The fact that roles are emitted a ref structs should be kept an implementation detail.  
As far as the language goes, roles would be a new kind of type. A role type would satisfy 
the same generic constraints as its underlying type.

```
role Role : SomeClassType;
void M<T>() where T : class { }
M<Role>(); // okay, `modopt(Role) Underlying`, Roslyn metadata reader can recover `Role`. Can reflection see custom modifiers?
```


