Description
General proposal
protected
modifier acts the same as private
in terms of code generation and assignability, except that it is possible to access a protected
member in any subclass of a class which declared the member. Basically, you can access protected members in the same situations where it would have been an error for you to redeclare a private
member with the same name as a base class's member.
Examples
class Base {
protected myMember;
}
class Derived extends Base {
foo() { return this.myMember; } // OK
}
var x = new Derived();
console.log(x.myMember); // Error, cannot access
class Derived2 extends Base {
private myMember; // Error, cannot tighten visibility
public myMember; // Error, cannot widen visibility
}
Open Questions
After the last design meeting, the following open questions remained:
Is 'sibling' property access allowed?
C# and other IL languages prohibit this pattern, but Java allows it:
class Base { protected x: string; }
class Derived extends Base {
foo(n: Base) {
// Not allowed: cannot reference protected member through base class reference
console.log(n.x);
}
}
See these links for reasoning
http://blogs.msdn.com/b/ericlippert/archive/2008/03/28/why-can-t-i-access-a-protected-member-from-a-derived-class-part-two-why-can-i.aspx
http://stackoverflow.com/questions/1904782/whats-the-real-reason-for-preventing-protected-member-access
Are protected
members subject to the "same-declaration" rule as private
members for assignability/subtyping?
private
members are considered equivalent for the purposes of assignability and subtyping if they are from the "same declaration". This isn't quite the rule you would want for protected members. Consider some classes:
class Widget {
protected inspector: WidgetInspector;
}
class SquareWidget extends Widget {
// Use a more-specific 'inspector'
protected inspector: SquareWidgetInspector;
}
class CircleWidget extends Widget {
// Initialize here
protected inspector: WidgetInspector = new WidgetInspector();
}
var w: Widget;
var c: CircleWidget;
w = c; // Allowed, or not?
If we took the verbatim "same declaration" rule from private
, this assignment would be disallowed because w.inspector
and c.inspector
come from different declarations. It's not reasonable to have this assignment be disallowed.
However, if we do not use the "same declaration" rule, then a SquareWidget
would be assignable to a CirceWidget
even if they both removed their extends
clauses. This is not surprising if you're used to thinking about things structurally, but since many people seem to like the higher specificity of private
in terms of preventing assignability between structurally-equivalent types, this behavior might not be desirable.
A proposed rule was that we could have a notion of a "parent" declaration when a derived class's property overrides a base class property. This seems tractable for classes, but interfaces can extend
multiple classes, and we would need to define what exactly that means. A degenerate example:
interface WatWidget1 extends Widget, CircleWidget { }
interface WatWidget2 extends Widget, SquareWidget { }
var ww1: WatWidget1;
var ww2: WatWidget2;
ww1 = new Widget(); // Allowed or not?
ww1 = new CircleWidget(); // Allowed or not?
ww2 = new Widget(); // Allowed or not?
ww2 = new CircleWidget(); // Allowed or not?
ww1 = ww2;
ww2 = ww1;
Can public properties be assigned to protected fields?
class Point1 { x: number }
var p1: Point1 = { x: 3 }; // Allowed
class Point2 { private x: number }
var p2: Point2 = { x: 3 }; // Disallowed
class Point3 { protected x: number }
var p: Point3 = { x: 3 }; // Allowed or not?
This is sort of a yes-or-no thing tangentially related to the previous question.