www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Virtual functions and inheritance

reply "David Monagle" <david.monagle intrica.com.au> writes:
Hi guys,

I'm a former C++ developer and really enjoying working with D 
now. I have a question that I hope some of you may be able to 
answer.

class Parent {
    property string typeName() {
     return typeof(this).stringof;
   }
}

class Child : Parent {
}

void main() {
   auto p = new Parent;
   auto c = new Child;
   assert(p.typeName == "Parent");
   assert(p.typeName == "Child");
}


I'm looking for an explanation as to why this doesn't work, then 
a suggestion for how I may achieve child classes being able to 
generate a string description of their own type, without 
redefining the typeName property on each child. (I'm currently 
solving this with a mixin, but I was hoping for a better solution.

I'm assuming it doesn't work because either typeof(this) or 
.stringof is evaluated at compile time?
Jan 26 2015
next sibling parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Tue, Jan 27, 2015 at 04:38:57AM +0000, David Monagle via Digitalmars-d-learn
wrote:
 Hi guys,
 
 I'm a former C++ developer and really enjoying working with D now. I
 have a question that I hope some of you may be able to answer.
 
 class Parent {
    property string typeName() {
     return typeof(this).stringof;
   }
 }
Try this: class Parent { property string typeName() { return typeid(this).toString(); } }
 class Child : Parent {
 }
 
 void main() {
   auto p = new Parent;
   auto c = new Child;
   assert(p.typeName == "Parent");
   assert(p.typeName == "Child");
Bug: the second assert should have c.typeName. :-) But I got what you mean.
 }
 
 
 I'm looking for an explanation as to why this doesn't work, then a
 suggestion for how I may achieve child classes being able to generate
 a string description of their own type, without redefining the
 typeName property on each child. (I'm currently solving this with a
 mixin, but I was hoping for a better solution.
 
 I'm assuming it doesn't work because either typeof(this) or .stringof
 is evaluated at compile time?
typeof(this) is evaluated at compile-time. To get runtime information, you need to use typeid(). Of course, with my suggested change your code still won't work as-is, because typeid().toString() returns a fully-qualified name, so if your source file is test.d, it would return "test.Parent" and "test.Child". But you should be able to work with that. :-) T -- The volume of a pizza of thickness a and radius z can be described by the following formula: pi zz a. -- Wouter Verhelst
Jan 26 2015
parent "David Monagle" <david.monagle intrica.com.au> writes:
I can certainly work with that. Thank you very much! (and for 
pointing out my typo in the example)
Jan 26 2015
prev sibling next sibling parent reply Daniel =?UTF-8?B?S296w6Fr?= via Digitalmars-d-learn writes:
V Tue, 27 Jan 2015 04:38:57 +0000
David Monagle via Digitalmars-d-learn
<digitalmars-d-learn puremagic.com> napsáno:

 Hi guys,
 
 I'm a former C++ developer and really enjoying working with D 
 now. I have a question that I hope some of you may be able to 
 answer.
 
 class Parent {
     property string typeName() {
      return typeof(this).stringof;
    }
 }
 
 class Child : Parent {
 }
 
 void main() {
    auto p = new Parent;
    auto c = new Child;
    assert(p.typeName == "Parent");
    assert(p.typeName == "Child");
 }
 
 
 I'm looking for an explanation as to why this doesn't work, then 
 a suggestion for how I may achieve child classes being able to 
 generate a string description of their own type, without 
 redefining the typeName property on each child. (I'm currently 
 solving this with a mixin, but I was hoping for a better solution.
 
 I'm assuming it doesn't work because either typeof(this) or 
 .stringof is evaluated at compile time?
You can use this T: class Parent { property string typeName(this T)() { return T.stringof; } } class Child : Parent { } void main() { auto p = new Parent; auto c = new Child; assert(p.typeName == "Parent"); assert(c.typeName == "Child"); }
Jan 27 2015
next sibling parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Tuesday, 27 January 2015 at 08:19:46 UTC, Daniel Kozák wrote:
 You can use this T:

 class Parent {
      property string typeName(this T)() {
         return T.stringof;
     }
 }

 class Child : Parent {
 }

 void main() {
     auto p = new Parent;
     auto c = new Child;

     assert(p.typeName == "Parent");
     assert(c.typeName == "Child");
 }
OTOH: void main() { auto p = new Parent; auto c = new Child; assert(p.typeName == "Parent"); assert(c.typeName == "Child"); p = c; assert(p.typeName == "Parent"); } It will still use the static type of the object that it's called on, not the dynamic type.
Jan 27 2015
prev sibling parent reply "Baz" <bb.temp gmx.com> writes:
On Tuesday, 27 January 2015 at 08:19:46 UTC, Daniel Kozák wrote:
 You can use this T:

 class Parent {
      property string typeName(this T)() {
         return T.stringof;
     }
 }

 class Child : Parent {
 }

 void main() {
     auto p = new Parent;
     auto c = new Child;

     assert(p.typeName == "Parent");
     assert(c.typeName == "Child");
 }
Could 'this T' be used for a static constructor ? ----- class Bar { static T construct(this T, A...)(A a) { return new T(a); } } ---- doesn't work. And similarly to the the orginal post: ----- class Bar { static typeof(this) construct(A...)(A a) { return new typeof(this)(a); } } class Foo: Bar{} Foo foo= Foo.construct; // fail ---- construct() won't be redefined in the Bar descendants.
Jan 27 2015
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Baz:

 doesn't work. And similarly to the the orginal post:
I suggest to read some D documentation first, and program later. Bye, bearophile
Jan 27 2015
prev sibling parent "Tobias Pankrath" <tobias pankrath.net> writes:
 -----
 class Bar
 {
     static T construct(this T, A...)(A a)
     {
         return new T(a);
     }
 }
 ----
I think it's a bug that you can use a template this parameter (this T) on a static member function without a direct compilation error.
 -----
 class Bar
 {
     static typeof(this) construct(A...)(A a)
     {
         return new typeof(this)(a);
     }
 }
Because it's exactly the same to write it as static Bar construct(A...)(A a) { return new Bar(a); } Of course this does not work. I don't know how to do it without one line of boilerplate per class or without supplying the type via template argument. std.container.util : make takes the type to construct as an argument, but std.container do not form a class hierarchy.
Jan 27 2015
prev sibling parent reply "Baz" <bb.temp gmx.com> writes:
On Tuesday, 27 January 2015 at 04:38:59 UTC, David Monagle wrote:
 Hi guys,

 I'm a former C++ developer and really enjoying working with D 
 now. I have a question that I hope some of you may be able to 
 answer.

 class Parent {
    property string typeName() {
     return typeof(this).stringof;
   }
 }

 class Child : Parent {
 }

 void main() {
   auto p = new Parent;
   auto c = new Child;
   assert(p.typeName == "Parent");
   assert(p.typeName == "Child");
 }


 I'm looking for an explanation as to why this doesn't work, 
 then a suggestion for how I may achieve child classes being 
 able to generate a string description of their own type, 
 without redefining the typeName property on each child. (I'm 
 currently solving this with a mixin, but I was hoping for a 
 better solution.

 I'm assuming it doesn't work because either typeof(this) or 
 .stringof is evaluated at compile time?
This is almost the same code as written initially, let somone explain why the hell this is working: --- module test; import std.conv; class Parent { property final string typeName() { return to!string(this); } } class Child : Parent { } void main() { auto p = new Parent; auto c = new Child; assert(p.typeName == __MODULE__ ~ ".Parent"); assert(c.typeName == __MODULE__ ~ ".Child"); } ---
Jan 29 2015
next sibling parent "Baz" <bb.temp gmx.com> writes:
even more weird:

---
module test;
import std.conv;

interface Meh{
     final string typeName()
     {return to!string(this);}
}

class Parent : Meh {}

class Child : Parent {}

void main() {
   auto p = new Parent;
   auto c = new Child;
   assert(p.typeName == __MODULE__ ~ ".Parent");
   assert(c.typeName == __MODULE__ ~ ".Child");
}
---
Jan 29 2015
prev sibling parent "Tobias Pankrath" <tobias pankrath.net> writes:
 This is almost the same code as written initially,
 let somone explain why the hell this is working:

 ---
 module test;
 import std.conv;

 class Parent {
    property final string typeName() {
     return to!string(this);
   }
 }

 class Child : Parent {
 }

 void main() {
   auto p = new Parent;
   auto c = new Child;
   assert(p.typeName == __MODULE__ ~ ".Parent");
   assert(c.typeName == __MODULE__ ~ ".Child");
 }
 ---
Because to!string calls toString, which is a virtual function. It's the same as the NVI-Idiom in C++.
Jan 29 2015