www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - abstract function templates

reply Nrgyzer <nrgyzer gmail.com> writes:
Hey guys,

I've the following class:

abstract class Drawable {

	public {

		uint getHeight() { ... }
		uint getWidth() { ... }

		abstract {
			void draw(T = void*)(uint zPos, T obj = null);
		}

	}

}

When I compile this code, it compiles without any errors.

Now... I have the following class:

class Texture : Drawable {

	public {

		override {
			void draw(T = void*)(uint zPos, T obj = null)
{ ... }
		}

	}

}

When I create a new instance of Texture and try to call
newInstance.draw(50), I always get the following error:

"Error: variable Texture.draw!(void*).draw.this override cannot be
applied to variable"
"Error: variable Texture.draw!(void*).draw.zPos override cannot be
applied to variable"
"Error: variable Texture.draw!(void*).draw.pbo override cannot be
applied to variable"
"Error: variable ... Texture.draw!(void*).draw.zPos override cannot
be applied to variable"

I hope anyone can help me - thanks!
Dec 26 2010
next sibling parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Nrgyzer <nrgyzer gmail.com> wrote:

 I hope anyone can help me - thanks!

D currently does not support virtual template functions (and thus overriding such). The solution (if you can call it that) is to simply not mark draw with override, and perhaps remove it from the base class. -- Simen
Dec 26 2010
next sibling parent Nrgyzer <nrgyzer gmail.com> writes:
Ah, okay - remove override is enough.

Thanks :)
Dec 26 2010
prev sibling parent Nrgyzer <nrgyzer gmail.com> writes:
I just figured out that this doesn't work, when I use a array with
super class as base type, for example: Drawable[] textures;

Then, I'll get the following error:

"Error: function draw!(void*).draw non-virtual functions cannot be
abstract".

I just implemented the draw-function as empty function, which doesn't
create any errors, but I seems that it's not calling the draw-
function of any texture instance. It seems that it is always calling
Drawable.draw() - the empty function. When I create a new instance of
my Texture-class, it calls the draw-function of the texture-instance.
Dec 26 2010
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I think this is relevant:
http://www.digitalmars.com/d/2.0/template.html : "Limitations":

Templates cannot be used to add non-static members or virtual
functions to classes.
Templates cannot add functions to interfaces.

But I'm a little confused as to how it all works out. This will work:

import std.stdio;

class Foo
{
    void draw(T)(T t) { writeln("Foo"); };
}

class Bar : Foo
{
    /* override */ void draw(T)(T t) { writeln("Bar"); };
}

void main()
{
    Bar bar = new Bar();
    bar.draw(1); // "Bar"
    (cast(Foo)bar).draw(1); // "Foo"
}

But uncomment the override and it fails.

Experts will have to chime in on this one. :)
Dec 26 2010
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
Andrej Mitrovic wrote:
 I think this is relevant:
 http://www.digitalmars.com/d/2.0/template.html : "Limitations":

 Templates cannot be used to add non-static members or virtual
 functions to classes.
 Templates cannot add functions to interfaces.

 But I'm a little confused as to how it all works out. This will work:

 import std.stdio;

 class Foo
 {
     void draw(T)(T t) { writeln("Foo"); };
 }

 class Bar : Foo
 {
     /* override */ void draw(T)(T t) { writeln("Bar"); };
 }

Bar.draw does not override, but "hide" Foo.draw. They are unrelated functions.
 void main()
 {
     Bar bar = new Bar();
     bar.draw(1); // "Bar"

Bar.draw!int is called. No virtual dispatch is involved, as Foo.draw!int doesn't even exist.
     (cast(Foo)bar).draw(1); // "Foo"

Now Foo.draw!int is instantiated (at compile time) an is called. There is no Bar.draw!int instantiated at all.
 }

 But uncomment the override and it fails.

That's because "Templates cannot be used to add [...] virtual functions to classes" Ali
Dec 28 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Ali Çehreli:

  > But uncomment the override and it fails.
 
 That's because "Templates cannot be used to add [...] virtual functions 
 to classes"

But the error messages given by DMD 2.051 aren't easy to understand for me: test.d(10): Error: variable test.Bar.draw!(int).draw.this override cannot be applied to variable test.d(10): Error: variable test.Bar.draw!(int).draw.t override cannot be applied to variable Bye, bearophile
Dec 28 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

 Agreed. Can you file a bug report?

Sorry, but I don't understand the topic enough yet (I don't know why templated methods can't be virtual), so I leave the bug report to someone else that's able to write something meaningful in the bug report :-) Bye, bearophile
Dec 28 2010
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
bearophile wrote:
 (I don't know why templated methods can't be virtual), so I leave the 

the bug report :-) I created a bug report just about the compiler error message: http://d.puremagic.com/issues/show_bug.cgi?id=5387 I think the compiler rejects the code according to spec. Ali
Dec 28 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Nrgyzer <nrgyzer gmail.com> wrote:

 I just figured out that this doesn't work, when I use a array with
 super class as base type, for example: Drawable[] textures;

 Then, I'll get the following error:

 "Error: function draw!(void*).draw non-virtual functions cannot be
 abstract".

 I just implemented the draw-function as empty function, which doesn't
 create any errors, but I seems that it's not calling the draw-
 function of any texture instance. It seems that it is always calling
 Drawable.draw() - the empty function. When I create a new instance of
 my Texture-class, it calls the draw-function of the texture-instance.

Yes indeed. This was what I meant by saying that template functions cannot be virtual. D sadly has no way to create templated functions that work in a class hierarchy. :( -- Simen
Dec 26 2010
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/27/10, Simen kjaeraas <simen.kjaras gmail.com> wrote:
 Yes indeed. This was what I meant by saying that template functions
 cannot be virtual. D sadly has no way to create templated functions
 that work in a class hierarchy. :(

Does it really make sense for a class to have methods that accept any type of argument? It's one thing to have a class specialized on some type(s), e.g.: class Foo(T1, T2) { void bar(T1 var, T2 etc) { } } But having a class method which can accept any type, that seems odd to me. I don't know since I've never used such a thing before, but maybe it has some good use cases? (I'd love to know about those btw!). You can introduce constraints, but I thought having parameterized classes would solve most of the use-case scenarios.
Dec 26 2010
parent Nrgyzer <nrgyzer gmail.com> writes:
The sense is that I have different, drawable classes/object - for
example a simple texture (not clickable) and a button (clickable).
When the user clicks the mouse, the obj-param which is defined by
using draw!(T = void*)(uint zPos, T obj = null) will be saved in a
template-struct which should have the type of obj -> struct myStruct
(T). The advantage is, that I can use the obj referenced in the
struct without any casting.

I just solved the problem by declaring draw() as final-function and
used a new value as callback in the final draw()-function - for
example:

...
private void delegate() drawCallback;

public final void draw(T = void*)(uint zPos, T obj = null) {

	drawCallback();

	// ... do additional work
}
Dec 26 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:

 Does it really make sense for a class to have methods that accept any
 type of argument? It's one thing to have a class specialized on some
 type(s), e.g.:

 class Foo(T1, T2)
 {
     void bar(T1 var, T2 etc) { }
 }

 But having a class method which can accept any type, that seems odd to
 me. I don't know since I've never used such a thing before, but maybe
 it has some good use cases? (I'd love to know about those btw!).

Well, operator overloading comes to mind. Certainly for types that would allow mathematical operations with any generic numeric type.
 You can introduce constraints, but I thought having parameterized
 classes would solve most of the use-case scenarios.

-- Simen
Dec 26 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday 26 December 2010 16:18:19 Simen kjaeraas wrote:
 Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 Does it really make sense for a class to have methods that accept any
 type of argument? It's one thing to have a class specialized on some
 type(s), e.g.:
 
 class Foo(T1, T2)
 {
 
     void bar(T1 var, T2 etc) { }
 
 }
 
 But having a class method which can accept any type, that seems odd to
 me. I don't know since I've never used such a thing before, but maybe
 it has some good use cases? (I'd love to know about those btw!).

Well, operator overloading comes to mind. Certainly for types that would allow mathematical operations with any generic numeric type.

In many cases, it would make sense to make virtual functions which have all of the types that make sense and then have a templated function called in each of them so that their implementation is still shared. A big problem with having template functions be virtual is the fact that such functions don't exist until they're called, whereas a class and its virtual function need to exist regardless of whether the functions get called - particularly when you bring libraries into it. - Jonathan M Davis
Dec 26 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Jonathan M Davis <jmdavisProg gmx.com> wrote:

 A big problem with having template functions be virtual is the fact that  
 such
 functions don't exist until they're called, whereas a class and its  
 virtual
 function need to exist regardless of whether the functions get called -
 particularly when you bring libraries into it.

I'm very aware of that. The only possibility I see would be to build vtables at startup (sorta also possible at link-time), and I think we can all agree that's an uncomfortable nest of worms. -- Simen
Dec 26 2010
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Thanks, Ali! :)
Dec 28 2010
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 12/28/10, bearophile <bearophileHUGS lycos.com> wrote:
 But the error messages given by DMD 2.051 aren't easy to understand for me:

 test.d(10): Error: variable test.Bar.draw!(int).draw.this override cannot be
 applied to variable
 test.d(10): Error: variable test.Bar.draw!(int).draw.t override cannot be
 applied to variable

Agreed. Can you file a bug report?
Dec 28 2010
prev sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
bearophile <bearophileHUGS lycos.com> wrote:

 (I don't know why templated methods can't be virtual)

First of all, they can. But it's a shitload of extra work, and requires that compilation be mixed up with linking. Whenever a templated method is used from any subclass, it has to be generated for the base class, and any and all subclasses that override it. We can't know every subclass until link-time (not even then, given dynamic linking). -- Simen
Dec 28 2010