Thread overview
Access derived type in baseclass static function template
Aug 02, 2017
Timoses
Aug 02, 2017
Timoses
Aug 02, 2017
Arafel
Aug 02, 2017
Timoses
Aug 03, 2017
Timoses
Aug 02, 2017
Arafel
Aug 03, 2017
Timoses
August 02, 2017
Hey,

wondering whether it's possible to access the derived type from a function template in the base class or interface.

this T does not seem to be working, I guess because it's a static function and this does not exists?!


interface I
{
    static void test(this T)()
    {
        writeln(T.type.stringof);
    }
}

abstract class A
{
    static void test(this T)()
    {
        writeln(T.type.stringof);
    }
}

class B : A
{
    alias type = uint;
}
class C : I {
    alias type = int;
}

void main() {
	B.test();
	C.test();
}

Throws:
Error: template app.A.test cannot deduce function from argument types !()(), candidates are:
        app.A.test(this T)()
Error: template app.I.test cannot deduce function from argument types !()(), candidates are:
        app.I.test(this T)()


Any way I could accomplish this?
August 02, 2017
On 8/2/17 8:07 AM, Timoses wrote:
> Hey,
> 
> wondering whether it's possible to access the derived type from a function template in the base class or interface.
> 
> this T does not seem to be working, I guess because it's a static function and this does not exists?!

Yep.

> Any way I could accomplish this?

Move test outside the interface:

void test(C)(C c) if(is(C : I))
{
   writeln(C.type.stringof);
}

Though, at that point, you don't need I. I'm assuming you have a more complex real-world example.

-Steve
August 02, 2017
On Wednesday, 2 August 2017 at 12:49:12 UTC, Steven Schveighoffer wrote:
> On 8/2/17 8:07 AM, Timoses wrote:
>> Hey,
>> 
>> wondering whether it's possible to access the derived type from a function template in the base class or interface.
>> 
>> this T does not seem to be working, I guess because it's a static function and this does not exists?!
>
> Yep.
>
>> Any way I could accomplish this?
>
> Move test outside the interface:
>
> void test(C)(C c) if(is(C : I))
> {
>    writeln(C.type.stringof);
> }
>
> Though, at that point, you don't need I. I'm assuming you have a more complex real-world example.
>
> -Steve

Thanks for the reply!

Not sure I understand correctly, though.

interface I {}
class A : I {}

void test(T)(T t) if(is(T: I))
{ writeln(T.type.stringof); }

void main()
{
    A.test;
}

throws:
  Error: no property 'test' for type 'app.A'

which it of course does... test(A) makes no sense either.
I need to call it statically and want to know the derived class type in the base class (or interface) function template.

Is there a trick in your answer? : P
August 02, 2017
On 08/02/2017 02:07 PM, Timoses wrote:
> Hey,
> 
> wondering whether it's possible to access the derived type from a function template in the base class or interface.
> 
> this T does not seem to be working, I guess because it's a static function and this does not exists?!
> 
> 

[...]

> 
> Any way I could accomplish this?

Well, it's a clumsy workaround, but the only thing missing seems to be the "this T" automatic deduction. I was recently hit by something similar: the "this" parameter deduction only works for instance methods.

It was not totally clear if it was a bug or a feature... The documentation [1] is however quite clear:

> TemplateThisParameters are used in member function templates to pick up the type of the this reference. 

So, static functions doesn't seem to be covered.

You can, however, make it explicit:

```
B.test!B();
C.test!C();
```

And then even alias it to prevent accidental mismatches:

```
import std.stdio;

interface I
{
    static void test(this T)()
    {
        writeln(T.type.stringof);
    }
}

abstract class A
{
    static void test(this T)()
    {
        writeln(T.type.stringof);
    }
}

class B : A
{
    alias type = uint;
}
class C : I {
    alias type = int;
}

void main() {
    test!B();
    test!C();
}

alias test(T) = T.test!T;
```

[1]: http://dlang.org/spec/template.html#TemplateThisParameter
August 02, 2017
On 8/2/17 9:11 AM, Timoses wrote:
> On Wednesday, 2 August 2017 at 12:49:12 UTC, Steven Schveighoffer wrote: Thanks for the reply!
> 
> Not sure I understand correctly, though.
> 
> interface I {}
> class A : I {}
> 
> void test(T)(T t) if(is(T: I))
> { writeln(T.type.stringof); }
> 
> void main()
> {
>      A.test;
> }
> 
> throws:
>    Error: no property 'test' for type 'app.A'
> 
> which it of course does... test(A) makes no sense either.
> I need to call it statically and want to know the derived class type in the base class (or interface) function template.
> 
> Is there a trick in your answer? : P

Sorry, I didn't read your original post thoroughly, you need an instance to make this work properly.

A a;
a.test; // should work

What you are looking for is virtual static methods, and D doesn't have those. I don't know if there's a way to make it work with existing features.

However, your original code has potential as an enhancement request, as the type is known at compile-time and could certainly be resolved to pass in as the `this` template parameter.

-Steve
August 02, 2017
> 
> What you are looking for is virtual static methods, and D doesn't have those. I don't know if there's a way to make it work with existing features.
> 

Well, there are interesting things to do:

https://dpaste.dzfl.pl/ed826ae21473

I don't know if that's what one would call "virtual static", but I'd say it comes close...
August 02, 2017
Thanks Arafel, the alias workaround might just be a nice way to put it.

On Wednesday, 2 August 2017 at 13:51:01 UTC, Steven Schveighoffer wrote:
> What you are looking for is virtual static methods, and D doesn't have those. I don't know if there's a way to make it work with existing features.

I'm not looking to overwrite the static method (which would refer to virtual, right?).

The solution I had previously was:

interface I
{
    static void test(T)()
    {
        writeln(T.stringof);
    }
}

class B : I {
    alias type = int;

    static void test()
    {
        I.test!type();
    }
}

void main()
{
    B.test();
}

However, this requires to add the base type as in
  I.test!type();
otherwise (only test!type();) it complains about
  Error: template instance test!type test is not a template declaration, it is a function

I was hoping there was a way to simply define it in the base class/interface without producing redundant code in each derived class.

Arafel's solution gets very close!

On Wednesday, 2 August 2017 at 13:51:01 UTC, Steven Schveighoffer wrote:
> However, your original code has potential as an enhancement request, as the type is known at compile-time and could certainly be resolved to pass in as the `this` template parameter.

I guess the `this` is really misleading it being a static method.
I suppose https://issues.dlang.org/buglist.cgi?bug_severity=enhancement&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&product=D&query_format=report-table&y_axis_field=bug_severity would be the place for an enhancement request?
Possibly related:
https://issues.dlang.org/show_bug.cgi?id=14191


On Wednesday, 2 August 2017 at 14:23:26 UTC, Arafel wrote:
>
>> 
>> What you are looking for is virtual static methods, and D doesn't have those. I don't know if there's a way to make it work with existing features.
>> 
>
> Well, there are interesting things to do:
>
> https://dpaste.dzfl.pl/ed826ae21473
>
> I don't know if that's what one would call "virtual static", but I'd say it comes close...

Nifty, but still doesn't allow knowing the derived type B in the foo method of A, does it?
August 02, 2017
On 8/2/17 11:06 AM, Timoses wrote:
> On Wednesday, 2 August 2017 at 13:51:01 UTC, Steven Schveighoffer wrote:
>> However, your original code has potential as an enhancement request, as the type is known at compile-time and could certainly be resolved to pass in as the `this` template parameter.
> 
> I guess the `this` is really misleading it being a static method.
> I suppose https://issues.dlang.org/buglist.cgi?bug_severity=enhancement&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&product=D&query_format=report-table&y_axis_field=bug_severity would be the place for an enhancement request?
> Possibly related:
> https://issues.dlang.org/show_bug.cgi?id=14191

Yes, that's exactly it.

Note that typeof(this) has special meaning for static methods:

class C
{
   static typeof(this) foo() { return new typeof(this); }
}

So there is precedence for the meaning of `this` in a static context.

-Steve
August 03, 2017
On Wednesday, 2 August 2017 at 12:07:46 UTC, Timoses wrote:
> Hey,
>
> wondering whether it's possible to access the derived type from a function template in the base class or interface.
>
> [...]

Created an enhancement issue:

https://issues.dlang.org/show_bug.cgi?id=17714
August 03, 2017
On Wednesday, 2 August 2017 at 15:38:12 UTC, Steven Schveighoffer wrote:
> On 8/2/17 11:06 AM, Timoses wrote:
>> On Wednesday, 2 August 2017 at 13:51:01 UTC, Steven Schveighoffer wrote:
>>> However, your original code has potential as an enhancement request, as the type is known at compile-time and could certainly be resolved to pass in as the `this` template parameter.
>> 
>> I guess the `this` is really misleading it being a static method.
>> I suppose https://issues.dlang.org/buglist.cgi?bug_severity=enhancement&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&product=D&query_format=report-table&y_axis_field=bug_severity would be the place for an enhancement request?
>> Possibly related:
>> https://issues.dlang.org/show_bug.cgi?id=14191
>
> Yes, that's exactly it.
>
> Note that typeof(this) has special meaning for static methods:
>
> class C
> {
>    static typeof(this) foo() { return new typeof(this); }
> }
>
> So there is precedence for the meaning of `this` in a static context.
>
> -Steve

Oh, just now get it after creating the issue ^^. Makes sense. I kind of connected the "this" to existing instances because the DMD compiler often complains about something like "need this for..." when calling something from a static method that... well... needs "this" or instantiation..
E.g.:

class A
{
    static void a()
    {
        b();
    }
    void b();
}

will throw
  Error: need 'this' for 'b' of type 'void()'