www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Defining and overriding methods of an abstract base class which must

reply pineapple <meapineapple gmail.com> writes:
This is essentially what I'm trying to accomplish. The intuitive 
solution, of course, does not work. In theory I could write a 
separate method for every anticipated return type, but that would 
be horrible and in that case I'd probably just write the damn 
thing in a dynamically-typed language instead.

     import std.conv;

     abstract class BaseClass{
         abstract X convertSomePropertyTo(X)();
     }

     class SubClass(T): BaseClass{
         T property;
         X convertSomePropertyTo(X)(){
             return property.to!X;
         }
     }

     void main(){
         BaseClass obj = new SubClass!int;
         auto x = obj.convertSomePropertyTo!real; // Error: 
function 
test.BaseClass.convertSomePropertyTo!real.convertSomePropertyTo 
non-virtual functions cannot be abstract
     }
Jul 10 2016
parent reply Basile B. <b2.temp gmx.com> writes:
On Sunday, 10 July 2016 at 21:06:42 UTC, pineapple wrote:
 This is essentially what I'm trying to accomplish. The 
 intuitive solution, of course, does not work. In theory I could 
 write a separate method for every anticipated return type, but 
 that would be horrible and in that case I'd probably just write 
 the damn thing in a dynamically-typed language instead.

     import std.conv;

     abstract class BaseClass{
         abstract X convertSomePropertyTo(X)();
     }

     class SubClass(T): BaseClass{
         T property;
         X convertSomePropertyTo(X)(){
             return property.to!X;
         }
     }

     void main(){
         BaseClass obj = new SubClass!int;
         auto x = obj.convertSomePropertyTo!real; // Error: 
 function 
 test.BaseClass.convertSomePropertyTo!real.convertSomePropertyTo 
 non-virtual functions cannot be abstract
     }
The problem you encounter here is that templatized functions cannot be virtual. If you remove "abstract" and put an empty body than it works, but you lose the whole OOP thing, i.e you cannot call the most derived override from the base. ==== import std.conv; abstract class BaseClass { auto convertSomePropertyTo(X)(){}; } class SubClass(T): BaseClass { T property; X convertSomePropertyTo(X)() { return property.to!X; } } void main() { SubClass!int obj = new SubClass!int; auto x = obj.convertSomePropertyTo!real; } === We are many to encounter this issue. It comes from the fact that the VTBL cannot be build from a template.
Jul 10 2016
next sibling parent Basile B. <b2.temp gmx.com> writes:
On Sunday, 10 July 2016 at 21:20:34 UTC, Basile B. wrote:
 On Sunday, 10 July 2016 at 21:06:42 UTC, pineapple wrote:
 [...]
It comes from the fact that the VTBL cannot be build from a template.
See https://issues.dlang.org/show_bug.cgi?id=1657#c1
Jul 10 2016
prev sibling parent reply pineapple <meapineapple gmail.com> writes:
On Sunday, 10 July 2016 at 21:20:34 UTC, Basile B. wrote:
 The problem you encounter here is that templatized functions 
 cannot be virtual. If you remove "abstract" and put an empty 
 body than it works, but you lose the whole OOP thing, i.e you 
 cannot call the most derived override from the base.
Yeah, that was the first thing I tried, and it took me a while and some measure of annoyance to realize the base method was being called instead of the derived one. Surely there's some reasonable workaround?
Jul 10 2016
next sibling parent Basile B. <b2.temp gmx.com> writes:
On Sunday, 10 July 2016 at 21:27:14 UTC, pineapple wrote:
 On Sunday, 10 July 2016 at 21:20:34 UTC, Basile B. wrote:
 The problem you encounter here is that templatized functions 
 cannot be virtual. If you remove "abstract" and put an empty 
 body than it works, but you lose the whole OOP thing, i.e you 
 cannot call the most derived override from the base.
Yeah, that was the first thing I tried, and it took me a while and some measure of annoyance to realize the base method was being called instead of the derived one. Surely there's some reasonable workaround?
AFAIK no. OOP and templates don't mix well as main paradigm. This doesn't mean that templates can't be used in OOP (eg as template param for a class of for some helpers used in virtual function) but you see that one can break the other.
Jul 10 2016
prev sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Sunday, July 10, 2016 21:27:14 pineapple via Digitalmars-d-learn wrote:
 On Sunday, 10 July 2016 at 21:20:34 UTC, Basile B. wrote:
 The problem you encounter here is that templatized functions
 cannot be virtual. If you remove "abstract" and put an empty
 body than it works, but you lose the whole OOP thing, i.e you
 cannot call the most derived override from the base.
Yeah, that was the first thing I tried, and it took me a while and some measure of annoyance to realize the base method was being called instead of the derived one. Surely there's some reasonable workaround?
You can have an abstract non-templated function which then calls a templated function in the derived class' implementation, and you can have a templated function in the base class which then calls an abstract, non-templated function that the derived class implements. But if you actually need the templated function to be virtual, then there is no way to do it. For instance, overloaded operators usually can't be virtual in D, because most of them are templated. However, a workaround for them is to declare the overloaded operator on the base class and then have it call a non-templated function which the derived classes override. e.g. a typical opBinary would look something like class C { C opBinary(string op)(C rhs) if(["+, "-", "*", "-"].canFind(op)) { mixin("return this.value " ~ op ~ " rhs.value;"); } int value; } but that can't be virtual. So, you if you need virtual, overloaded operators, then you do something like class C { C opBinary(string op)(C rhs) if(op == "=") { return doAdd(rhs); } C opBinary(string op)(C rhs) if(op == "-") { return doSub(rhs); } C opBinary(string op)(C rhs) if(op == "*") { return doMul(rhs); } C opBinary(string op)(C rhs) if(op == "/") { return doDiv(rhs); } protected abstract C doAdd(C c); protected abstract C doSub(C c); protected abstract C doMul(C c); protected abstract C doDiv(C c); int value; } But that only works, because you're not really dealing with an arbitrary list of possible, template arguments. If you really need it to work with a list of unknown, possible, template arguments, then you're out of luck. The only way that you're going to get what you're trying to do to work is if you can find a way to define a non-templated function (or set of functions) that can be virtual and do the work that you need to be virtual. - Jonathan M Davis
Jul 10 2016