The subject says it all, here is a sample:
module m1;
class M1
{
protected void foo() {}
}
module m2;
import m1;
class M2 : public M1
{
void bar()
{
M1 m1 = new M1();
m1.foo(); // fails*
M2 m2 = new M2();
m2.foo(); // ok
}
}
* m2.d(9): class m1.M1 member foo is not accessible
Comment #1 by jarrett.billingsley — 2008-10-14T07:51:36Z
Good luck convincing Walter on this one. He refused to budge on it four years ago, citing that "this is the way C++ does it and it must have gotten it right." I call bullshit on that, but whatever.
Comment #2 by bruno.do.medeiros+deebugz — 2008-10-17T14:14:41Z
It fails because protected does not give access to outside types that are not of type M2. the protected attribute is giving access to the derived class ONLY in the case where the instance IS derived to the same type.
i.e.:
class A
{
protected byte[] getSecretKey() {return null;}
}
// protect B from being overridden, to protect getSecretKey
final class B : A
{
protected override byte[] getSecretKey()
{
// generate a special key that only classes
// of type B should know
}
}
class C : A
{
byte[] backdoor(A a) { return a.getSecretKey(); }
}
Protected is guaranteeing to class B's author that nobody can get at the function except for classes that actually derive from B.
Comment #4 by jarrett.billingsley — 2008-10-17T15:24:59Z
When you want to do this, there is no really reasonable way around it. You make the method protected, subclasses can't call it. You make it private, no one can call it. You make it package, only classes at the same level in the package hierarchy can call it. You make it public, anyone can call it. There is no good solution. There is no way to say "this method can be overridden or called from derived classes and nowhere else," which is ostensibly more useful than "this method can only be overridden in derived classes."
Comment #5 by schveiguy — 2008-10-17T15:43:23Z
(In reply to comment #4)
> When you want to do this, there is no really reasonable way around it. You
> make the method protected, subclasses can't call it.
Yes they can, they can call it on their own instance, or on instances of the same class. i.e. the following should work:
if(auto x = cast(M2)m1)
{
x.foo();
}
> You make it private, no
> one can call it. You make it package, only classes at the same level in the
> package hierarchy can call it. You make it public, anyone can call it. There
> is no good solution. There is no way to say "this method can be overridden or
> called from derived classes and nowhere else,"
What you are asking for is 'overridden or called from any class that derived from my base class'. Protected functions already can be called from derived classes in their own instance or in instances of their own type. Another class may not want you to be able to call their protected function simply by inheriting its base class.
If we listed all the 'protection schemes' that people wanted, I'm sure there would be at least a dozen. Should all these be implemented?
Comment #6 by aarti — 2008-10-17T16:25:50Z
I also think that proposed behavior would be useful. There were few cases where I actually needed such a behavior.
It would be useful e.g. for clone() function, where you have to create new object of specific class, and then setup it before return. You might want to make some properties of this object only changeable for class and its descendant, and in such a case you are stuck... Either you make your properties public or you will not have access to these properties.
It might be something similar as access to private members from same module, which was Walter's experiment, but was fully successful, although no other language implements it.
Comment #7 by schveiguy — 2008-10-18T10:41:44Z
clone does not need a different behavior, this should work:
class C
{
protected int x;
C clone()
{
auto ret = new C;
ret.x = x;
return ret;
}
}
I don't see the problem.
Comment #8 by schveiguy — 2008-10-18T10:43:41Z
(In reply to comment #7)
> clone does not need a different behavior, this should work:
>
> class C
> {
> protected int x;
> C clone()
> {
> auto ret = new C;
> ret.x = x;
> return ret;
> }
> }
>
> I don't see the problem.
>
err.. that was a bad example, add this:
class C : D
{
protected int y;
D clone()
{
auto ret = new D;
ret.x = x;
ret.y = y;
}
}
Comment #9 by schveiguy — 2008-10-18T10:44:36Z
(In reply to comment #8)
> err.. that was a bad example, add this:
>
> class C : D
D'oh! should have been
class D : C
mind no worky today.
Comment #10 by aarti — 2008-10-18T16:21:07Z
(In reply to comment #9)
Indeed, it works... I would swear that it doesn't, because I remember some problems with access in inheritance hierarchy... But maybe it was original case which was given here, I don't remember right now...
In that case, I think the spec should be changed to reflect the current behavior. I think Walter wanted it to model after the way C++ works, and it just wasn't explained well enough.
Without the current behavior (i.e. allowing m2.foo to be callable), functions like clone would be difficult to implement.
I think the spec should be changed to say:
"If accessing a protected instance member through a derived class member function, that member can only be accessed for an object instance which can be implicitly cast to the same type as 'this'."
Comment #13 by github-bugzilla — 2012-01-22T16:46:02Z