
# C# Language Design Notes for Feb 25th, 2019

## Agenda

Semantics of `base()` calls in default interface implementations and classes

## Discussion

The exact semantics of `base()` are still unresolved. Consider
the following legacy `base` call.

```C#
class A 
{
    virtual void M() {}
}

class B : A 
{ 
    // override void M() { }
}

class C : B
{
    override void M() => base.M();
}
```

The behavior for `base` is to find the "nearest" implementation and call
that implementation using a direct call, meaning if B.M is uncommented it
will be called, while if it commented out then A.M will be called. Notably,
if `B` is uncommented at compile time, but at runtime the `B.M` override is
not present *the runtime will call A.M.* This is because the runtime will
continue looking through base classes for a matching signature if the target
method is not present.

Most importantly, the runtime *does not* yet have this behavior for `base()`
calls in interface implementations. This is because there could be multiple
paths to search down and the current IL encoding does not provide a root
definition to search towards.

For example,

```C#
interface IA
{
    void M();
}
interface IB : IA
{
    void IA.M() // If this gets removed, the IC.M call will fail
    {
        base(IA).M();
    }
}
interface IC : IB
{
    void IA.M() => base(IB).M();
}
```

At the moment, we do not have the time to implement an entire new IL form
for `base()` calls, so we have to implement a behavior in absence of that
feature.

Choices:

1. No `base()` call
2. `base()` call can only target the original definition of the method
3. `base(T).M()` call is a direct call to `T` and an error if the method
doesn't exist
4. `base(T)` starts searching in `T`, but in the compiler looks at the bases
for a unique, most derived implementation.

For feature evolution, we then have three more choices later.

1. Stay as-is
2. New opcode/behavior for `base()`
3. New opcode/behavior for `base.` and `base()`

**Conclusion**

For the first choice, let's do (3). The emitted code will be a direct call to
that method. It is expected that the runtime will throw an exception if an
implementation is not present in that type. For binding, in classes the
signature used will be the closest override, while for interfaces the
signature will be the member definition.