www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - private vs protected in Interfaces

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
More code from TDPL:

import std.exception;

interface Transmogrifier
{
    final void thereAndBack() {}
    
    private:
        void transmogrify();
        void untransmogrify();
}

class CardboardBox : Transmogrifier
{
    private:
        override void transmogrify() { }
        override void untramsogrify() { }
}

class FlippableCardboardBox : CardboardBox
{
    private:
        bool flipped;
        override void transmogrify()
        {
            enforce(!flipped, "Can't transmogrify: box is in time machine
mode");
            super.transmogrify();   // should be an error, cannot invoke private
                                    // method CardboardBox.transmogrify
        }
        override void untransmogrify()
        {
        }
}

import std.stdio;

void main()
{
    auto obj = new FlippableCardboardBox;
    obj.transmogrify();
}

TPDL, page 216: "Making an overridable function private in an
interface..prevents an implementation from calling the super function".

But the code example above compiles and runs fine.

On the next page: "A simpler solution is to relax access of the two
overridables in Transmogrifier from private to protected:"

interface Transmogrifier
{
    final void thereAndBack() {}
    
    protected:
        void transmogrify();
        void untransmogrify();
}

This will not work. I get back:
test.d(13): Error: class test.CardboardBox interface function
Transmogrifier.transmogrify isn't implemented
test.d(13): Error: class test.CardboardBox interface function
Transmogrifier.untransmogrify isn't implemented
test.d(20): Error: class test.FlippableCardboardBox interface function
Transmogrifier.transmogrify isn't implemented
test.d(20): Error: class test.FlippableCardboardBox interface function
Transmogrifier.untransmogrify isn't implemented
test.d(20): Error: class test.FlippableCardboardBox interface function
Transmogrifier.transmogrify isn't implemented
test.d(20): Error: class test.FlippableCardboardBox interface function
Transmogrifier.untransmogrify isn't implemented

Which doesn't make any sense, the derived classes have the functions
implemented. 

Btw Andrei, you threw that enforce in without any explanation (I don't think I
saw it in any earlier examples), and you're missing an import (but I've put
that in the errata).
Aug 13 2010
parent reply Christian Kamm <kamm-incasoftware removethis.de> writes:
Andrej Mitrovic wrote:

 TPDL, page 216: "Making an overridable function private in an
 interface..prevents an implementation from calling the super function".
 
 But the code example above compiles and runs fine.
 
See http://d.puremagic.com/issues/show_bug.cgi?id=4542 . By the D spec, private implies final. That means unimplemented private methods in interfaces have little use. Also 'private override' should be an error. Or spec and compiler should be changed to be in line with TDPL. Christian
Aug 13 2010
next sibling parent reply Jonathan M Davis <jmdavisprog gmail.com> writes:
On Friday 13 August 2010 23:14:02 Christian Kamm wrote:
 Andrej Mitrovic wrote:
 TPDL, page 216: "Making an overridable function private in an
 interface..prevents an implementation from calling the super function".
 
 But the code example above compiles and runs fine.
See http://d.puremagic.com/issues/show_bug.cgi?id=4542 . By the D spec, private implies final. That means unimplemented private methods in interfaces have little use. Also 'private override' should be an error. Or spec and compiler should be changed to be in line with TDPL. Christian
Generally speaking, if the spec and TDPL are in conflict, TDPL is supposed to win. Still, until Walter says something about it or it's fixed, we won't know for sure. I really do think that TDPL should win out in this case though. It would not be good to be unable to do NVI. - Jonathan M Davis
Aug 13 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 08/14/2010 01:20 AM, Jonathan M Davis wrote:
 On Friday 13 August 2010 23:14:02 Christian Kamm wrote:
 Andrej Mitrovic wrote:
 TPDL, page 216: "Making an overridable function private in an
 interface..prevents an implementation from calling the super function".

 But the code example above compiles and runs fine.
See http://d.puremagic.com/issues/show_bug.cgi?id=4542 . By the D spec, private implies final. That means unimplemented private methods in interfaces have little use. Also 'private override' should be an error. Or spec and compiler should be changed to be in line with TDPL. Christian
Generally speaking, if the spec and TDPL are in conflict, TDPL is supposed to win. Still, until Walter says something about it or it's fixed, we won't know for sure. I really do think that TDPL should win out in this case though. It would not be good to be unable to do NVI.
I think TDPL should win in this case. Andrei
Aug 14 2010
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
Jonathan M Davis wrote:

  It would not be good to be unable to do NVI.
I am not saying that it should not be supported; but... I've used NVI a number of times myself until I was convinced by Kevlin Henney that it was "a solution in search of a problem" during one of his many excellent presentations at the Silicon Valley ACCU: http://www.accu-usa.org/Slides/ACriticalViewOfCppPractices.pdf A couple of slides can't convey his thoughts, but here they are: <quote slide="27"> Non-virtual Interfaces? NVI suggests virtuals should be private and wrapped in public non-virtuals Over the last decade or so this has been proposed by some as a good practice guideline It has structural similarities with Template Method, but has a distinct form and (in)distinct motivation However, it is a solution in search of a problem On close inspection the problems it purports to resolve are better addressed by other more mature and proven techniques, e.g. the Interceptor pattern </quote> <quote slide="28"> Non-Valuable Idiom NVI lacks either a clear motivation or a clear description of benefits Motivation is often presented in terms of shotgun speculation — code simplification, instrumentation, extensibility, decoupling, thread safety, assertion checking, etc. — that does not stand up to scrutiny NVI singularly fails to adequately offer the benefits that are advertised as its motivation In practice it is a somewhat tedious and verbose technique that adds baggage to a class hierarchy </quote> Ali
Aug 15 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 08/15/2010 04:01 AM, Ali Çehreli wrote:
 Jonathan M Davis wrote:

 It would not be good to be unable to do NVI.
I am not saying that it should not be supported; but... I've used NVI a number of times myself until I was convinced by Kevlin Henney that it was "a solution in search of a problem" during one of his many excellent presentations at the Silicon Valley ACCU: http://www.accu-usa.org/Slides/ACriticalViewOfCppPractices.pdf
Interesting. I think Kevlin is an outstanding designer, and I agree with him that applying NVI as a convention in languages that have little support for it is tenouos. I disagree with a few points his slides make, and am informing him of this discussion to allow him to chime in if he wants. * Slide 17: Ironically, this slides provides motivation for NVI without recognizing it. * Slide 27: "On close inspection... more mature and proven techniques, e.g. the Interceptor pattern". Maturity and proven-worthiness would suggest that most everyone should have heard of the Interceptor pattern. I knew nothing about the name so I googled for it. Google only finds 1420 hits for "interceptor pattern" compared to the 76000 hits for "non virtual interface" (both quoted to eliminate noise). I'm not saying numbers are an ultimate argument, but I find it specious that a mature and proven technique has only 1420 hits to speak for it (not to mention that the Wikipedia entry is quite underwhelming). * Slide 28: "NVI lacks either a clear motivation or a clear description of benefits" with a scathing sub-bullet. Going to the first google hit for "non virtual interface" (wikibooks.org) shows the following intent: "To modularize/refactor common before and after code fragments (e.g., invariant checking, acquiring/releasing locks) for an entire class hierarchy at one location." Not only I find it hard to frame that motivator as unclear speculation etc., but I actually find it pretty darn good. * Slide 29: The example given illustrates either an unrealistic mocking or a misunderstanding of the pattern: instead of offering _distinct_ interfaces to clients and children, it offers the same exact interface, just written twice. The one thing that sucks about NVI is the scant language support for it, issue alluded to slide 24. I would have agreed with 4 slides worth of detail on that one. In C++ a derived class is free to break NVI in quite a number of ways, notably by wrongly overriding (actually hiding) functions that aren't virtual. So in C++ NVI is clunky to enact and difficult to even maintain. I hope we fixed those in D (implementation bugs notwithstanding). Andrei
Aug 15 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Andrei Alexandrescu wrote:
 On 08/15/2010 04:01 AM, Ali Çehreli wrote:
 Jonathan M Davis wrote:

 It would not be good to be unable to do NVI.
I am not saying that it should not be supported; but... I've used NVI a number of times myself until I was convinced by Kevlin Henney that it was "a solution in search of a problem" during one of his many excellent presentations at the Silicon Valley ACCU: http://www.accu-usa.org/Slides/ACriticalViewOfCppPractices.pdf
Interesting. I think Kevlin is an outstanding designer, and I agree with him that applying NVI as a convention in languages that have little support for it is tenouos. I disagree with a few points his slides make, and am informing him of this discussion to allow him to chime in if he wants.
[snip] Just got word from Kevlin that he's on vacation with family, so he won't reply to this anytime soon. Andrei
Aug 16 2010
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I agree, NVI really looks like a nice idiom/pattern to me, I'd hate to loose
it.

On Sat, Aug 14, 2010 at 8:20 AM, Jonathan M Davis <jmdavisprog gmail.com>wrote:

 On Friday 13 August 2010 23:14:02 Christian Kamm wrote:
 Andrej Mitrovic wrote:
 TPDL, page 216: "Making an overridable function private in an
 interface..prevents an implementation from calling the super function".

 But the code example above compiles and runs fine.
See http://d.puremagic.com/issues/show_bug.cgi?id=4542 . By the D spec, private implies final. That means unimplemented private methods in interfaces have little use. Also 'private override' should be
an
 error.

 Or spec and compiler should be changed to be in line with TDPL.

 Christian
Generally speaking, if the spec and TDPL are in conflict, TDPL is supposed to win. Still, until Walter says something about it or it's fixed, we won't know for sure. I really do think that TDPL should win out in this case though. It would not be good to be unable to do NVI. - Jonathan M Davis
Aug 14 2010
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On page 217+218 there are two interfaces that define some final methods with
the same name, and a class that inherits from both:

interface Timer
{
    final void run() {}
}

interface Application
{
    final void run() {}
}

class TimedApp : Timer, Application
{
    void run() {}    // cannot define run()
}

Okay, it hijacks both methods which are final, it won't compile which is
what we want.
TDPL states: "To access those methods for app of type TimedApp, you'd have
to write app.Timer.run() and app.Application.run() for Timer's and
Application's version", where the inheriting class does not hijack the
methods.

So that would look like this:

interface Timer
{
    final void run() {};
}

interface Application
{
    final void run() {};
}

class TimedApp : Timer, Application
{
}

import std.stdio;

void main()
{
    auto app = new TimedApp;
    app.Timer.run();  // error, no Timer property
    app.Application.run(); // error, no Application property
}

This looks to me like a DMD bug? I know I can do calls like these if a class
inherits from another class:

class Timer
{
    final void run() {};
}

class Application
{
    final void run() {};
}

class TimedApp : Timer//, Application
{
}

import std.stdio;

void main()
{
    auto app = new TimedApp;
    app.Timer.run();  // works fine
    //~ app.Application.run();
}

(Note I've had to comment out inheriting Application since MI is disallowed
in D). This will now run. Is this a DMD bug?


On Sat, Aug 14, 2010 at 4:56 PM, Andrej Mitrovic <andrej.mitrovich gmail.com
 wrote:
 I agree, NVI really looks like a nice idiom/pattern to me, I'd hate to
 loose it.
Aug 14 2010