Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

base(T) - Draft Specification #2910

Open
gafter opened this issue Oct 25, 2019 · 5 comments
Open

base(T) - Draft Specification #2910

gafter opened this issue Oct 25, 2019 · 5 comments

Comments

@gafter
Copy link
Member

gafter commented Oct 25, 2019

See also #2337

We add support for a new expression form base(T). This is similar to the existing base form. The section numbers in the following is based on the ECMA specification.

12.7.N Explicit base access (new spec section)

An explicit_base_access consists of the keyword base followed by a type between parentheses followed by either a . token and an identifier and optional type_argument_list or an argument_list enclosed in square brackets:

explicit_base_access
    : 'base' '(' type ')' '.' identifier type_argument_list?
    | 'base' '(' type ')' '[' argument_list ']'
    ;

An explicit_base_access is used to access members of a base type or implemented interface. A explicit_base_access is permitted only in the body of an instance constructor, an instance method, an instance accessor (§12.2.1), or a finalizer. When base(T) occurs in an interface, class, or struct, T shall denote a base type or implemented interface of the enclosing type. When base(T).I occurs, I shall denote a member of T. Likewise, when base(T)[E]`` occurs, an applicable indexer shall exist in T`.

At binding-time, explicit_base_access expressions of the form base(T).I and base(T)[E]`` are evaluated exactly as if they were written ((T)this).Iand((T)this)[E]. Thus, base(T).Iandbase(T)[E] correspond to `this.I` and `this[E], except this is viewed as an instance of type T. When a explicit_base_access references a virtual function member (a method, property, or indexer), it is a compile-time error if there is no most specific implementation of that function member in T or its base types or interfaces.

When a explicit_base_access references a virtual function member (a method, property, or indexer), the determination of which function member to invoke at run-time (§12.6.6) is changed. The function member that is invoked is determined by finding the most derived implementation (§15.6.4) of the function member with respect to T (instead of with respect to the run-time type of this, as would be usual in a non-base access). Thus, within an override of a virtual function member, an explicit_base_access can be used to invoke an inherited implementation of the function member.

[Note: Unlike this, but like base, base(T)` is not an expression in itself. It is a syntax form only used in the context of a explicit_base_access. end note]

8.5.4 Protected access

The specification for protected access has a list of the syntactic forms which are permitted and allow accessing a protected member. To that list we add the following:

  • a primary_expression of the form base(T).M

When the specification is corrected to describe protected access for indexers, that correction should be extended to handle the base(T) form as well.

Translation

An explicit_base_access would be translated to a possibly new IL sequence per feature request https://github.com/dotnet/coreclr/issues/25156.

@YairHalberstadt
Copy link
Contributor

At binding-time, explicit_base_access expressions of the form base(T).I and base(T)[E]`` are evaluated exactly as if they were written ((T)this).Iand((T)this)[E].

Does this mean you can't access protected members via this syntax?

@gafter
Copy link
Member Author

gafter commented Oct 26, 2019

Good point. I will make an amendment to 8.5.4 Protected access to indicate that the new base(T) form is one of the ways that a protected member may be used.

@jzabroski
Copy link

I believe the way languages like Beta handle the protected member issue is with an "inner" keyword that allows the base class to specify whether it is safe to call the protected member. The paper Super and Inner - Together At Last!, describes some gotchas and solutions.

@gafter
Copy link
Member Author

gafter commented Dec 17, 2019

Two open issues need to be tracked for this:

  1. What if we have base(I).GetHashCode() for a method defined in an interface? Does it call the method in the interface or the one in object which any class that impleemnts I would implicitly take as its implementation?
  2. What should the runtime's behavior be for a base(C) call, where C is a class type, but the identified method is an interface method implemented in C by a virtual method (perhaps with a compiler bridge)? The syntax does not support this today, but we might consider wanting it to be supported in the future.

@hamarb123
Copy link

Hi, just wondering when this feature is planned to be added, I'm really looking forward to it (it's one of my 3 most wanted features along with static abstract interface members, and extension everything)!
Also, just wanted to check that code like this would work as I expect:

Code in this 'spoiler'
public interface IA
{
	public void Method1() => Console.WriteLine("1");
	public void Method2() => Console.WriteLine("2");
}
public interface IB : IA
{
	void IA.Method2() => Console.WriteLine("Not 2");
}
public class Class1 : IB
{
	public virtual void Method1() => Console.WriteLine("3");
	public virtual void Method2() => Console.WriteLine("4");
}
public class Class2 : Class1
{
	public void Print()
	{
		base(IA).Method1();
		base(IA).Method2();
		base(IB).Method2();
		base(Class1).Method1();
		base(Class1).Method2();
	}
	public override void Method1() => Console.WriteLine("Not 3");
	public override void Method2() => Console.WriteLine("Not 4");
}
The print function would print "1", "2", "Not 2", "3", "4". Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants