www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Shouldn't private methods be virtual too?

reply Michel Fortin <michel.fortin michelf.com> writes:
The following example prints "Base.foo" (using GDC 0.24), even though 
we have a Derived object and Derived's foo is declared as overriding 
Base's. Is that expected behaviour?

	module test.privatevirtualfunction;

	class Base {
		private void foo() { writefln("Base.foo"); }
	}

	class Derived : Base {
		override private void foo() { writefln("Derived.foo"); }
	}
	
	int main(char[][] args) {
		Base base = new Derived;
		base.foo();
		return 0;
	}

I understand that private currently makes the method non-virtual. I 
think this would be fine with the C++ private concept where it limits 
the member's usage to the current class, but I believe in D, where 
private only limits usage to the current module, you should be able to 
override that method in any class defined in the same module. If that's 
not the case, then you should at the very least get an error with the 
above code.

Making Base's method public or protected changes the output to 
"Derived.foo" as I'd expect.

-- 
Michel Fortin
michel.fortin michelf.com
http://michelf.com/
Jun 10 2008
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Michel Fortin" <michel.fortin michelf.com> wrote in message 
news:g2lnj9$1ig9$1 digitalmars.com...
 The following example prints "Base.foo" (using GDC 0.24), even though we 
 have a Derived object and Derived's foo is declared as overriding Base's. 
 Is that expected behaviour?

 module test.privatevirtualfunction;

 class Base {
 private void foo() { writefln("Base.foo"); }
 }

 class Derived : Base {
 override private void foo() { writefln("Derived.foo"); }
 }

 int main(char[][] args) {
 Base base = new Derived;
 base.foo();
 return 0;
 }

 I understand that private currently makes the method non-virtual. I think 
 this would be fine with the C++ private concept where it limits the 
 member's usage to the current class, but I believe in D, where private 
 only limits usage to the current module, you should be able to override 
 that method in any class defined in the same module. If that's not the 
 case, then you should at the very least get an error with the above code.

I would expect an error too. In most languages with this kind of protection scheme, overriding a base class method with a method that is more protected is an error. It is in Java: class Fark { public void foo() { } } public class Bark extends Fark { protected void foo() { } } Gives the error "foo() in Bark cannot override foo() in Fark; attempting to assign weaker access privileges; was public." And if my memory serves me, C# works the same way. Private methods should always be final. They cannot be overridden by derived classes, even if they can be accessed by classes in the same module.
Jun 10 2008
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Michel Fortin" wrote
 The following example prints "Base.foo" (using GDC 0.24), even though we 
 have a Derived object and Derived's foo is declared as overriding Base's. 
 Is that expected behaviour?

 module test.privatevirtualfunction;

 class Base {
 private void foo() { writefln("Base.foo"); }
 }

 class Derived : Base {
 override private void foo() { writefln("Derived.foo"); }
 }

 int main(char[][] args) {
 Base base = new Derived;
 base.foo();
 return 0;
 }

 I understand that private currently makes the method non-virtual. I think 
 this would be fine with the C++ private concept where it limits the 
 member's usage to the current class, but I believe in D, where private 
 only limits usage to the current module, you should be able to override 
 that method in any class defined in the same module. If that's not the 
 case, then you should at the very least get an error with the above code.

 Making Base's method public or protected changes the output to 
 "Derived.foo" as I'd expect.

In answer to your subject, no. Private methods are methods used by a class that declares it only, not by derived classes. That is the expectation that an author should have when declaring a method private. If you want a method to be overridable by derived classes, declare it protected. In answer to your example, I agree there should be an error if you declare a method as 'override private'. -Steve
Jun 10 2008
prev sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Michel Fortin wrote:
 The following example prints "Base.foo" (using GDC 0.24), even though we 
 have a Derived object and Derived's foo is declared as overriding 
 Base's. Is that expected behaviour?
 
     module test.privatevirtualfunction;
 
     class Base {
         private void foo() { writefln("Base.foo"); }
     }
 
     class Derived : Base {
         override private void foo() { writefln("Derived.foo"); }
     }
     
     int main(char[][] args) {
         Base base = new Derived;
         base.foo();
         return 0;
     }
 
 I understand that private currently makes the method non-virtual. I 
 think this would be fine with the C++ private concept where it limits 
 the member's usage to the current class, but I believe in D, where 
 private only limits usage to the current module, you should be able to 
 override that method in any class defined in the same module. If that's 
 not the case, then you should at the very least get an error with the 
 above code.
 
 Making Base's method public or protected changes the output to 
 "Derived.foo" as I'd expect.

I agree, but last time I asked this it seemed like an unwinnable battle (everyone else said private should imply "final"). More controversial was whether "package" should imply "final" (which it does now, but I think it should not).
Jun 10 2008
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Robert Fraser" <fraserofthenight gmail.com> wrote in message 
news:g2n15d$2jo8$1 digitalmars.com...
 I agree, but last time I asked this it seemed like an unwinnable battle 
 (everyone else said private should imply "final"). More controversial was 
 whether "package" should imply "final" (which it does now, but I think it 
 should not).

I'll agree with you on "package". "package" should be entirely a visibility attribute. More or less it would function like 'protected' as long as the deriving class were in the same package; and 'private' if it weren't. Sigh.
Jun 10 2008
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2008-06-10 21:58:55 -0400, "Jarrett Billingsley" <kb3ctd2 yahoo.com> said:

 I'll agree with you on "package".  "package" should be entirely a visibility
 attribute.  More or less it would function like 'protected' as long as the
 deriving class were in the same package; and 'private' if it weren't.  Sigh.

Yeah, but private and package in D don't apply only to derived classes. Private means that any code in the same module may access the method, and package means any code in the same package may access the method. This is to avoid adding something alike the friend C++ keyword (anything in the same module is always a friend). There's noting to make a member "class-private" in D. By the way, protected methods can also be accessed from outside the class and its derivative if you're in the same module. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 10 2008
prev sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Jarrett Billingsley wrote:
 "Robert Fraser" <fraserofthenight gmail.com> wrote in message 
 news:g2n15d$2jo8$1 digitalmars.com...
 I agree, but last time I asked this it seemed like an unwinnable battle 
 (everyone else said private should imply "final"). More controversial was 
 whether "package" should imply "final" (which it does now, but I think it 
 should not).

I'll agree with you on "package". "package" should be entirely a visibility attribute. More or less it would function like 'protected' as long as the deriving class were in the same package; and 'private' if it weren't. Sigh.

"protected" and "package" are non-equivalent overlapping sets; neither one a subset of the other. "package" means anything in the package can access it, whether it's in a derived class or not. "protected" means that only thing in the derived class (or the same module as the item in question) should be able to access it, no matter what package they're in.
Jun 10 2008
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2008-06-10 19:02:13 -0400, Robert Fraser <fraserofthenight gmail.com> said:

 Making Base's method public or protected changes the output to 
 "Derived.foo" as I'd expect.

I agree, but last time I asked this it seemed like an unwinnable battle (everyone else said private should imply "final"). More controversial was whether "package" should imply "final" (which it does now, but I think it should not).

Ok, so we're two to think protection attributes should be orthogonal with the final attribute of a member function, although I can't say I'm strongly in favor of one or the other. Package and private are pretty much the same thing: one makes the function accessible to the current module only, the other makes the function accessible to the current package only. If one has the side effect of making the function final, then the other should too if we are to preserve consistency. As a side note, it's pretty amusing to see that even this compiles perfectly fine: class Base { final package void foo() { writefln("Base.foo"); } } class Derived : Base { override final package void foo() { writefln("Derived.foo"); } } In Functions[1], it is said that "Functions marked as final may not be overridden in a derived class, unless they are also private", so I take it to mean that it is correct to override a final private function in derived class, and by extension this is true for package functions too, and thus, there are no bugs here. Funny, isnt' it? [1]: http://www.digitalmars.com/d/2.0/function.html -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jun 10 2008
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Michel Fortin wrote:
 On 2008-06-10 19:02:13 -0400, Robert Fraser <fraserofthenight gmail.com> 
 said:
 
 Making Base's method public or protected changes the output to 
 "Derived.foo" as I'd expect.

I agree, but last time I asked this it seemed like an unwinnable battle (everyone else said private should imply "final"). More controversial was whether "package" should imply "final" (which it does now, but I think it should not).

Ok, so we're two to think protection attributes should be orthogonal with the final attribute of a member function, although I can't say I'm strongly in favor of one or the other. Package and private are pretty much the same thing: one makes the function accessible to the current module only, the other makes the function accessible to the current package only. If one has the side effect of making the function final, then the other should too if we are to preserve consistency.

I've thought a lot about this issue, and I believe you're right they /should/ be consistent here -- a "package" is a limited set of modules controlled (supposedly) by one programmer or a small team, so API changes aren't a deal here. However, if there's going to be some nonsensical restriction that "private" implies "final" making "package" imply "final" is simply too strong of a restriction. There's often times you want to expose a method within a package for convenience, but don't want it to be part of the public API. Since most class overriding takes place within a package, restricting there's enough of a need for virtual package function to justify the inconsistency. I'd rather make it so that the concepts were orthogonal , though.
 As a side note, it's pretty amusing to see that even this compiles 
 perfectly fine:
 
     class Base {
         final package void foo() { writefln("Base.foo"); }
     }
 
     class Derived : Base {
         override final package void foo() { writefln("Derived.foo"); }
     }
 
 In Functions[1], it is said that "Functions marked as final may not be 
 overridden in a derived class, unless they are also private", so I take 
 it to mean that it is correct to override a final private function in 
 derived class, and by extension this is true for package functions too, 
 and thus, there are no bugs here. Funny, isnt' it?
 
 [1]: http://www.digitalmars.com/d/2.0/function.html

Java figured out perfectly good semantics for package-protection years ago. Having "protected" and "private" accessible within the same module throws a wrench into it (i.e. we can't totally copy it), but why we need to tie concepts lie protection and virtuality together is beyond me.
Jun 10 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
Robert Fraser wrote:
 [...]

Sorry, that probably came off as a bit harsh. Everyone has one or two issues they care really strongly about (const, pure, whatever). This one's mine.
Jun 10 2008