www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - non virtual interfaces

reply Alexandr Druzhinin <drug2004 bk.ru> writes:
Hello all.

I try to use NVI and failed with a snippet from TDPL:

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

	private:
		void transmogrify();
		void untransmogrify();
}

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

int main()
{
	auto cb = new CardboardBox();
	return 0;
}

doesn't compile with log info:
src/test.d(16): Error: function test.CardboardBox.transmogrify cannot 
override a non-virtual function
src/test.d(17): Error: function test.CardboardBox.untransmogrify does 
not override any function, did you mean to override 
'test.Transmogrifier.untransmogrify'?

It rather well differs from what I expected reading TDPL. Something is 
changed very much or I just missed something?
Sep 19 2013
parent reply Alexandr Druzhinin <drug2004 bk.ru> writes:
if I use protected instead of private in interface like:
interface Transmogrifier
{
	final void thereAndBack()
	{
		transmogrify();
		untransmogrify();
	}

	protected:
		void transmogrify();
		void untransmogrify();
}

class CardboardBox: Transmogrifier
{
	override protected void transmogrify() { }
	override void untransmogrify() {}
}

int main()
{
	auto cb = new CardboardBox();
	return 0;
}

it compiles, but why does compiler permit making untransmogrify() be 
public? How can I prohibit this? May be it just unrealized yet?
Sep 19 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 09/19/2013 10:31 PM, Alexandr Druzhinin wrote:

 if I use protected instead of private in interface like:
private member functions are non-virtual.
 interface Transmogrifier
 {
      final void thereAndBack()
      {
          transmogrify();
          untransmogrify();
      }

      protected:
          void transmogrify();
          void untransmogrify();
 }
If they were non-virtual (i.e. private), the calls to transmogrify() and untransmogrify() from thereAndBack() would be bound to Transmogrifier.transmogrify and Transmogrifier.untransmogrify at compile time. That happens and the linker cannot find their definitions.
 class CardboardBox: Transmogrifier
 {
      override protected void transmogrify() { }
      override void untransmogrify() {}
 }
 it compiles, but why does compiler permit making untransmogrify() be
 public?
It is up to CardboardBox to decide whether untransmogrify() is public or not. Note that untransmogrify() is still protected when objects are used through the Transmogrifier interface. However, when an object is known to be a CardboardBox so that it is being used through the CardboardBox interface, it is not bound to be a Transmogrifier at that point. Yes, CardboardBox inherits from Transmogrifier but it is CardboardBox's interface that is being used at that point so it decides.
 How can I prohibit this? May be it just unrealized yet?
You cannot prohibit from Transmogrifier. Ali
Sep 19 2013
parent reply Alexandr Druzhinin <drug2004 bk.ru> writes:
20.09.2013 12:45, Ali Çehreli пишет:
 On 09/19/2013 10:31 PM, Alexandr Druzhinin wrote:

  > if I use protected instead of private in interface like:

 private member functions are non-virtual.
But I just use code example from TDPL russian edition. And TDPL says clearly that (un)transmogrify() are private and CardboardBox _maynot_ make (un)transmogrify() non-private - this is highlighted as compiler support of NVI idiom. Is it wrong example, I guess?
  > interface Transmogrifier
  > {
  >      final void thereAndBack()
  >      {
  >          transmogrify();
  >          untransmogrify();
  >      }
  >
  >      protected:
  >          void transmogrify();
  >          void untransmogrify();
  > }

 If they were non-virtual (i.e. private), the calls to transmogrify() and
 untransmogrify() from thereAndBack() would be bound to
 Transmogrifier.transmogrify and Transmogrifier.untransmogrify at compile
 time. That happens and the linker cannot find their definitions.
I see. Thanks, I understand it now better
  > class CardboardBox: Transmogrifier
  > {
  >      override protected void transmogrify() { }
  >      override void untransmogrify() {}
  > }

  > it compiles, but why does compiler permit making untransmogrify() be
  > public?

 It is up to CardboardBox to decide whether untransmogrify() is public or
 not. Note that untransmogrify() is still protected when objects are used
 through the Transmogrifier interface. However, when an object is known
 to be a CardboardBox so that it is being used through the CardboardBox
 interface, it is not bound to be a Transmogrifier at that point. Yes,
 CardboardBox inherits from Transmogrifier but it is CardboardBox's
 interface that is being used at that point so it decides.
Thanks again. So there is no compiler support for NVI idiom? Because if CardboardBox may define its own (un)transmogrify() - TDPL says it possible only if (un)transmogrify() have other signatures.
  > How can I prohibit this? May be it just unrealized yet?

 You cannot prohibit from Transmogrifier.

 Ali
Unfortunately I tried to use NVI for it namely.
Sep 20 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 20, 2013 22:40:48 Alexandr Druzhinin wrote:
 20.09.2013 12:45, Ali =C3=87ehreli =D0=BF=D0=B8=D1=88=D0=B5=D1=82:
 On 09/19/2013 10:31 PM, Alexandr Druzhinin wrote:
  > if I use protected instead of private in interface like:
 private member functions are non-virtual.
=20 But I just use code example from TDPL russian edition. And TDPL says clearly that (un)transmogrify() are private and CardboardBox _maynot_=
 make (un)transmogrify() non-private - this is highlighted as compiler=
 support of NVI idiom. Is it wrong example, I guess?
TDPL is mostly correct but not completely correct. AFAIK, it has never = been=20 implemented that you can override private functions in interfaces like = TDPL=20 describes. With classes, package and private are _never_ virtual, so pr= ivate=20 will have be treated differently interfaces in order to do what TDPL de= scribes.=20 That may or may not be implemented in the future. You can use NVI with classes just fine just so long as you use protecte= d rather=20 than private, but making it private there won't work either, because pr= ivate=20 is never virtual (and it wouldn't really help you any if it were, becau= se=20 while the base class private function might not be callable, the derive= d class=20 one would still be callable by the derived class, so trying to prevent = the=20 virtual function in NVI from ever being called outside of the base clas= s is=20 broken in the first place - including in C++ where it was originally de= vised).=20 What NVI helps with is making it so that the public function being call= ed as=20 part of the API is non-virtual, allowing you to do stuff before and aft= er the=20 hidden virtual function being called, but the derived classes can still= call=20 their implementation of the hidden, virtual function. - Jonathan M Davis
Sep 20 2013
parent Alexandr Druzhinin <drug2004 bk.ru> writes:
20.09.2013 23:09, Jonathan M Davis пишет:
 You can use NVI with classes just fine just so long as you use protected rather
 than private, but making it private there won't work either, because private
 is never virtual (and it wouldn't really help you any if it were, because
 while the base class private function might not be callable, the derived class
 one would still be callable by the derived class, so trying to prevent the
 virtual function in NVI from ever being called outside of the base class is
 broken in the first place - including in C++ where it was originally devised).
 What NVI helps with is making it so that the public function being called as
 part of the API is non-virtual, allowing you to do stuff before and after the
 hidden virtual function being called, but the derived classes can still call
 their implementation of the hidden, virtual function.

 - Jonathan M Davis
I see. Thanks for clarifying.
Sep 20 2013