www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 2417] New: protected base member is not available via base hanlde in a derived class if it is defined in a separate module

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417

           Summary: protected base member is not available via base hanlde
                    in a derived class if it is defined in a separate module
           Product: D
           Version: 2.019
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: 2korden gmail.com


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


-- 
Oct 13 2008
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #1 from jarrett.billingsley gmail.com  2008-10-14 07:51 -------
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.


-- 
Oct 14 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #2 from brunodomedeiros+bugz gmail.com  2008-10-17 14:14 -------
I also thought this behavior was strange. I checked how Java works, and
surprinsigly, it works the same!
(see http://java.sun.com/docs/books/jls/third_edition/html/names.html#62587 for
a description or
http://java.sun.com/docs/books/jls/third_edition/html/names.html#36191 for an
example)

But I still don't know what is the reason for it. Is there one, or did Java
just inherit C++'s mistake?


-- 
Oct 17 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #3 from schveiguy yahoo.com  2008-10-17 14:41 -------
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.


-- 
Oct 17 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #4 from jarrett.billingsley gmail.com  2008-10-17 15:24 -------
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."


-- 
Oct 17 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #5 from schveiguy yahoo.com  2008-10-17 15:43 -------
(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? --
Oct 17 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #6 from aarti interia.pl  2008-10-17 16:25 -------
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.


-- 
Oct 17 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #7 from schveiguy yahoo.com  2008-10-18 10:41 -------
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.


-- 
Oct 18 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #8 from schveiguy yahoo.com  2008-10-18 10:43 -------
(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; } } --
Oct 18 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #9 from schveiguy yahoo.com  2008-10-18 10:44 -------
(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. --
Oct 18 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417





------- Comment #10 from aarti interia.pl  2008-10-18 16:21 -------
(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...


-- 
Oct 18 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417


smjg iname.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |smjg iname.com
           Keywords|                            |accepts-invalid
            Summary|protected base member is not|protected base member is not
                   |available via base hanlde in|available via base handle in
                   |a derived class if it is    |a derived class if it is
                   |defined in a separate module|defined in a separate module
            Version|2.019                       |1.036




------- Comment #11 from smjg iname.com  2008-11-24 10:47 -------
http://www.digitalmars.com/d/1.0/attribute.html
http://www.digitalmars.com/d/2.0/attribute.html
"If accessing a protected instance member through a derived class member
function, that member can only be accessed for the object instance which is the
'this' object for the member function call."

So the bug is that m2.foo() passes, rather than that m1.foo() fails.


-- 
Nov 24 2008
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2417


schveiguy yahoo.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |schveiguy yahoo.com
           Keywords|                            |spec




------- Comment #12 from schveiguy yahoo.com  2008-11-24 10:58 -------
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'."


-- 
Nov 24 2008