May 30, 2008
BCS wrote:
> Reply to Walter,
> 
>> BCS wrote:
>>
>>> However in highly limited cases, this is not an issue.
>>> 1) the template members are enumerations (just build the whole set)
>>> 2) the function has no parameters (only one version can be built)
>>> 3) no general form of the template exists, only explicit
>>> specializations
>>> (ditto enum)
>>> 4) class scope aliases of member templates are used. (instance the
>>> template and stuff it in as a normal function)
>> True, but now you have the issue that minor, seemingly innocuous
>> changes to a template function can have dramatic changes to its
>> behavior. It's a lot easier to understand "template functions are not
>> virtual" than "template functions are not virtual except in these
>> rather complex scenarios."
>>
>> If you need virtual behavior from a template function, the best way is
>> to wrap a virtual function call within it.
>>
> 
> in my case, I need this syntax
> 
> this.Templet!("foo")(arg)
> 
> to be virtual.
> 
> The use case is inside of dparse where I have template code calling template code.
> 
> 

You could use a functor/proxy type thing.  That is return a separate object for each class level that has opCall overloaded.  The opCall could be templated.  The functor object probably could be generalized so that you could use it in any case you needed a virtual function (it could callback its owner by template or maybe delegate).

Of course that's more complex then a simple template virtual inheritance however it does provide more functionality as well.

-Joel
May 30, 2008
janderson wrote:
> You could use a functor/proxy type thing.  That is return a separate object for each class level that has opCall overloaded.  The opCall could be templated.  The functor object probably could be generalized so that you could use it in any case you needed a virtual function (it could callback its owner by template or maybe delegate).

I don't understand this. You seem to be suggesting moving the template to a functor and having inheritors of the original class return a different functor. But unless that functor is virtual, you simply can't do that. You'd need to call a different method for each inheritor, or you'd need inheritance with the functors. The former is not virtual; the latter simply returns us to the original problem.
May 30, 2008
Chris Wright wrote:
> janderson wrote:
>> You could use a functor/proxy type thing.  That is return a separate object for each class level that has opCall overloaded.  The opCall could be templated.  The functor object probably could be generalized so that you could use it in any case you needed a virtual function (it could callback its owner by template or maybe delegate).
> 
> I don't understand this. You seem to be suggesting moving the template to a functor and having inheritors of the original class return a different functor. But unless that functor is virtual, you simply can't do that. You'd need to call a different method for each inheritor, or you'd need inheritance with the functors. The former is not virtual; the latter simply returns us to the original problem.

Something like:

class A
{
  templateCallback()() {} //template
  TemplateMaker Templet() { return new TemplateMaker(this, templateCallbackFunc); }
}


class A : B
{
  templateCallback2()() {} //template
  TemplateMaker Templet() { return new TemplateMaker(this, templateCallbackFunc2); }
}


Then the templateMaker would be:

class TemplateMaker(class, callback) //Functor/proxy
{
   TemplateMaker(class, callback) { record of stuff ... }

   void opCall(T...)(T arg) { recordedclass->recoredcallback(arg); }
}

Call it like:

this.Templet()!("foo")(arg)

//Might simplify to due to D's magic property stuff
this.Templet!("foo")(arg)

Something like that. Haven't tried it so don't know what massaging would be needed and if it would work.

-Joel
May 30, 2008
Reply to janderson,

> You could use a functor/proxy type thing.  That is return a separate
> object for each class level that has opCall overloaded.  The opCall
> could be templated.  The functor object probably could be generalized
> so that you could use it in any case you needed a virtual function (it
> could callback its owner by template or maybe delegate).
> 
> Of course that's more complex then a simple template virtual
> inheritance however it does provide more functionality as well.
> 
> -Joel
> 

It would be simpler to use a string mixin to generate functions with the string encoded into the function name. It could get ugly but a non virtual template function could get around that. But still, the proposed solution is "possible" and a lot cleaner.


May 30, 2008
Reply to Chris,

> BCS wrote:
> 
> You can just use a switch statement, but that gets unmaintainable
> before too long.
> 

Offten, yes (to both parts), but if the return types and or thenumber and types of the arguments change you are sunk.


May 31, 2008
janderson wrote:
> Something like:
> 
> class A
> {
>   templateCallback()() {} //template
>   TemplateMaker Templet() { return new TemplateMaker(this, templateCallbackFunc); }
> }
> 
> 
> class A : B
> {
>   templateCallback2()() {} //template
>   TemplateMaker Templet() { return new TemplateMaker(this, templateCallbackFunc2); }
> }
> 
> 
> Then the templateMaker would be:
> 
> class TemplateMaker(class, callback) //Functor/proxy
> {
>    TemplateMaker(class, callback) { record of stuff ... }
> 
>    void opCall(T...)(T arg) { recordedclass->recoredcallback(arg); }
> }
> 
> Call it like:
> 
> this.Templet()!("foo")(arg)
> 
> //Might simplify to due to D's magic property stuff
> this.Templet!("foo")(arg)
> 
> Something like that. Haven't tried it so don't know what massaging would be needed and if it would work.
> 
> -Joel

If TemplateMaker is templated, then you can't return it, just an instantiation of it. This only allows you to access one template through it.

If TemplateMaker is not templated, then it requires virtual templates in order to work; it's expecting a BaseClass, and even if it got a DerivedClass, it only knows about the template on BaseClass, so that's what it uses.
May 31, 2008
Chris Wright wrote:
> janderson wrote:
>> Something like:
>>
>> class A
>> {
>>   templateCallback()() {} //template
>>   TemplateMaker Templet() { return new TemplateMaker(this, templateCallbackFunc); }
>> }
>>
>>
>> class A : B
>> {
>>   templateCallback2()() {} //template
>>   TemplateMaker Templet() { return new TemplateMaker(this, templateCallbackFunc2); }
>> }
>>
>>
>> Then the templateMaker would be:
>>
>> class TemplateMaker(class, callback) //Functor/proxy
>> {
>>    TemplateMaker(class, callback) { record of stuff ... }
>>
>>    void opCall(T...)(T arg) { recordedclass->recoredcallback(arg); }
>> }
>>
>> Call it like:
>>
>> this.Templet()!("foo")(arg)
>>
>> //Might simplify to due to D's magic property stuff
>> this.Templet!("foo")(arg)
>>
>> Something like that. Haven't tried it so don't know what massaging would be needed and if it would work.
>>
>> -Joel
> 
> If TemplateMaker is templated, then you can't return it, just an instantiation of it. This only allows you to access one template through it.
> 
> If TemplateMaker is not templated, then it requires virtual templates in order to work; it's expecting a BaseClass, and even if it got a DerivedClass, it only knows about the template on BaseClass, so that's what it uses.

Sorry, I haven't actually tried this example.  Its an C++ trick I've used for other purposes.  I think it looks something like this:

class TemplateMaker
{
   TemplateMakera(delegate) { record of stuff ... } //This might be a template too, can't remember. Maybe a reinterpret cast somewhere too.
   void opCall(T...)(T arg) { delegate->recoredcallback(arg); }
}

I'm sure given enough time it could be done in D like C++.  I don't want to put in the effort though atm.

-Joel
May 31, 2008
janderson wrote:
> Sorry, I haven't actually tried this example.  Its an C++ trick I've used for other purposes.  I think it looks something like this:
> 
> class TemplateMaker
> {
>    TemplateMakera(delegate) { record of stuff ... } //This might be a template too, can't remember. Maybe a reinterpret cast somewhere too.
>    void opCall(T...)(T arg) { delegate->recoredcallback(arg); }
> }
> 
> I'm sure given enough time it could be done in D like C++.  I don't want to put in the effort though atm.
> 
> -Joel

Delegates can work. But you have to know the arguments to the template in advance.

Everything I can think of to implement virtual templates requires virtual templates. With the exception of hacking the compiler, which would provide a means of providing virtual templates. It's a straightforward matter, so it wouldn't require redesign like const, though the initial effort might well be greater.
June 01, 2008
Chris Wright wrote:
> janderson wrote:
>> Sorry, I haven't actually tried this example.  Its an C++ trick I've used for other purposes.  I think it looks something like this:
>>
>> class TemplateMaker
>> {
>>    TemplateMakera(delegate) { record of stuff ... } //This might be a template too, can't remember. Maybe a reinterpret cast somewhere too.
>>    void opCall(T...)(T arg) { delegate->recoredcallback(arg); }
>> }
>>
>> I'm sure given enough time it could be done in D like C++.  I don't want to put in the effort though atm.
>>
>> -Joel
> 
> Delegates can work. But you have to know the arguments to the template in advance.
> 
> Everything I can think of to implement virtual templates requires virtual templates. With the exception of hacking the compiler, which would provide a means of providing virtual templates. It's a straightforward matter, so it wouldn't require redesign like const, though the initial effort might well be greater.

I agree that having virtual templates in the language would be nice.  I don't like using workaround because they are less intuitive.

-Joel
June 14, 2008
BCS wrote:
> Reply to Walter,
> 
>> BCS wrote:
>>
>>> in my case, I need this syntax
>>>
>>> this.Templet!("foo")(arg)
>>>
>>> to be virtual.
>>>
>>> The use case is inside of dparse where I have template code calling
>>> template code.
>>>
>> You could try parameterizing the class enclosing the template, rather
>> than the template.
>>
> 
> I need to be able to have more than one version of the template
> 
> for a fuller example
> 
> class A
> {
>  void Template(char[] s: "foo")(int i) {writef("Hello %d\n", i);}
>  void Template(char[] s: "bob")(int i) {writef("See ya %d\n", i);}
> }
> 
> class B : A
> {
>  void Template(char[] s: "foo")(int i) {for(int j=0;j<i;j++) writef("Hello\n");}
>  void Template(char[] s: "bob")(int i) {for(int j=0;j<i;j++) writef("See ya\n");}}
> }
> 
> A a = someA();
> a.Template!("foo")(5);
> a.Template!("bob")(5); // same a, same class different function
> 
> 
> the actual used code looks something like this:
> 
> void CallIt(T,char[] str)(T it)
> {
>  it.Template!(str)(arg)
> }
> 
> (The reason for that form is rather complicated and irrelevant to this thread)
> 
> 

How about creating normal methods, and normal method override hierarchy/lineages, and then creating a template that simply selects the desired method lineage, like this:

--- ---
module test;

class A
{
  void Template_foo(int i) {writef("Hello %d\n", i);}
  void Template_bob(int i) {writef("See ya %d\n", i);}
  template Template(string s: "foo") { alias Template_foo Template; }
  template Template(string s: "bob") { alias Template_bob Template; }
}

class B : A
{
  override void Template_foo(int i) {for(int j=0;j<i;j++) writef("Hello\n");}
  override void Template_bob(int i) {for(int j=0;j<i;j++) writef("See ya\n");}
}

void main() {
	A a = new B();
	a.Template!("foo")(5);
	a.Template!("bob")(5); // same a, same class different function
}
--- ---
If you have many method choices, a mixin could be created to automatically generate all template specializations, such as:
  mixin TemplateAliases!("Template", ["foo", "bob", "bar", "xpto"]);
which would generate lines like:
  template Template(string s: "foo") { alias Template_foo Template; }
etc.

-- 
Bruno Medeiros - Software Developer, MSc. in CS/E graduate
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D