www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Determining whether a class has a method

reply Christopher Wright <dhasenan gmail.com> writes:
Hey all,

I'm trying to determine whether a class has a method (at compile time, 
based on the name), and ideally I want to do this is D1 as well as D2. 
In D2, I can just use __traits, of course.

I could try doing something like:

bool has_method(T, string name)() {
     foreach (method; T.tupleof) {
         if (method.stringof == name) {
             return true;
         }
     }
     return false;
}

But tupleof fails if you give it a class that has fields (methods are 
fine, but data fields aren't). I'm pretty sure this is a bug; can anyone 
else comment on it?

Is there a way to do this in D1?
Nov 29 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Christopher Wright wrote:
 Hey all,
 
 I'm trying to determine whether a class has a method (at compile time, 
 based on the name), and ideally I want to do this is D1 as well as D2. 
 In D2, I can just use __traits, of course.
 
 I could try doing something like:
 
 bool has_method(T, string name)() {
     foreach (method; T.tupleof) {
         if (method.stringof == name) {
             return true;
         }
     }
     return false;
 }
 
 But tupleof fails if you give it a class that has fields (methods are 
 fine, but data fields aren't). I'm pretty sure this is a bug; can anyone 
 else comment on it?
 
 Is there a way to do this in D1?
I think you may be able to use an 'is' check + string mixin if the name string is a compile time constant. like static if(is( T.name == function )) then mixin-ify that like bool has_method(T, string name) { mixin("static if(is T."~name~" == function)) " "{ return true; } else {return false; }"); } --bb
Nov 29 2007
parent reply Christopher Wright <dhasenan gmail.com> writes:
Bill Baxter wrote:
 I think you may be able to use an 'is' check + string mixin if the name 
 string is a compile time constant.
 like
    static if(is( T.name == function ))
 
 then mixin-ify that like
 
 bool has_method(T, string name) {
    mixin("static if(is T."~name~" == function)) "
          "{ return true; } else {return false; }");
 }
 
 
 --bb
Very nice! It works for every situation but the one I need: static if (is (T._ctor == function)) { // This never happens. } If there's no constructor defined for a class or any of its base classes, then ParameterTypeTuple!(T._ctor) fails, of course. I guess I can work around this by requiring an explicit constructor, but I don't love it, especially since I can't provide a helpful error message in the failing case.
Nov 29 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Christopher Wright wrote:
 Bill Baxter wrote:
 I think you may be able to use an 'is' check + string mixin if the
 name string is a compile time constant.
 like
    static if(is( T.name == function ))

 then mixin-ify that like

 bool has_method(T, string name) {
    mixin("static if(is T."~name~" == function)) "
          "{ return true; } else {return false; }");
 }


 --bb
Very nice! It works for every situation but the one I need: static if (is (T._ctor == function)) { // This never happens. } If there's no constructor defined for a class or any of its base classes, then ParameterTypeTuple!(T._ctor) fails, of course. I guess I can work around this by requiring an explicit constructor, but I don't love it, especially since I can't provide a helpful error message in the failing case.
Can't you do something like: static if( is( typeof(new T) == T ) ) ... That should fail if T doesn't have a zero-arg constructor, at least AFAIK. -- Daniel
Nov 29 2007
parent Christopher Wright <dhasenan gmail.com> writes:
Daniel Keep wrote:
 
 Christopher Wright wrote:
 Bill Baxter wrote:
 I think you may be able to use an 'is' check + string mixin if the
 name string is a compile time constant.
 like
    static if(is( T.name == function ))

 then mixin-ify that like

 bool has_method(T, string name) {
    mixin("static if(is T."~name~" == function)) "
          "{ return true; } else {return false; }");
 }


 --bb
Very nice! It works for every situation but the one I need: static if (is (T._ctor == function)) { // This never happens. } If there's no constructor defined for a class or any of its base classes, then ParameterTypeTuple!(T._ctor) fails, of course. I guess I can work around this by requiring an explicit constructor, but I don't love it, especially since I can't provide a helpful error message in the failing case.
Can't you do something like: static if( is( typeof(new T) == T ) ) ... That should fail if T doesn't have a zero-arg constructor, at least AFAIK. -- Daniel
With the implication that, if I have a zero-arg constructor, I can just use that, and if I don't, then I can safely call ParameterTypeTuple on it. Thanks!
Nov 29 2007
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Christopher Wright" <dhasenan gmail.com> wrote in message 
news:fink7k$6ph$1 digitalmars.com...

 But tupleof fails if you give it a class that has fields (methods are 
 fine, but data fields aren't). I'm pretty sure this is a bug; can anyone 
 else comment on it?
tupleof is supposed to give you a tuple of fields. It will never give methods.
Nov 29 2007
parent reply Christopher Wright <dhasenan gmail.com> writes:
Jarrett Billingsley wrote:
 "Christopher Wright" <dhasenan gmail.com> wrote in message 
 news:fink7k$6ph$1 digitalmars.com...
 
 But tupleof fails if you give it a class that has fields (methods are 
 fine, but data fields aren't). I'm pretty sure this is a bug; can anyone 
 else comment on it?
tupleof is supposed to give you a tuple of fields. It will never give methods.
And it's supposed to work for classes?
Nov 29 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Christopher Wright" <dhasenan gmail.com> wrote in message 
news:finqpt$lnj$2 digitalmars.com...
 Jarrett Billingsley wrote:
 "Christopher Wright" <dhasenan gmail.com> wrote in message 
 news:fink7k$6ph$1 digitalmars.com...

 But tupleof fails if you give it a class that has fields (methods are 
 fine, but data fields aren't). I'm pretty sure this is a bug; can anyone 
 else comment on it?
tupleof is supposed to give you a tuple of fields. It will never give methods.
And it's supposed to work for classes?
Yes. It's all in the spec: Class Properties The .tupleof property returns an ExpressionTuple of all the fields in the class, excluding the hidden fields and the fields in the base class.
Nov 29 2007
parent reply Christopher Wright <dhasenan gmail.com> writes:
Jarrett Billingsley wrote:
 "Christopher Wright" <dhasenan gmail.com> wrote in message 
 news:finqpt$lnj$2 digitalmars.com...
 Jarrett Billingsley wrote:
 "Christopher Wright" <dhasenan gmail.com> wrote in message 
 news:fink7k$6ph$1 digitalmars.com...

 But tupleof fails if you give it a class that has fields (methods are 
 fine, but data fields aren't). I'm pretty sure this is a bug; can anyone 
 else comment on it?
tupleof is supposed to give you a tuple of fields. It will never give methods.
And it's supposed to work for classes?
Yes. It's all in the spec: Class Properties The .tupleof property returns an ExpressionTuple of all the fields in the class, excluding the hidden fields and the fields in the base class.
Ah. Then it's not supposed to generate an error: Error: type Foo is not an expression For reference, here's the code, and I think it's not my error: class Foo { // Comment the following line to eliminate the error: // Error: type Foo is not an expression int i; } foreach (blah; Foo.tupleof) { writefln("%s", blah.stringof); } // or: auto a = Foo.tupleof[0];
Nov 29 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Christopher Wright wrote:
 Jarrett Billingsley wrote:
 "Christopher Wright" <dhasenan gmail.com> wrote in message 
 news:finqpt$lnj$2 digitalmars.com...
 Jarrett Billingsley wrote:
 "Christopher Wright" <dhasenan gmail.com> wrote in message 
 news:fink7k$6ph$1 digitalmars.com...

 But tupleof fails if you give it a class that has fields (methods 
 are fine, but data fields aren't). I'm pretty sure this is a bug; 
 can anyone else comment on it?
tupleof is supposed to give you a tuple of fields. It will never give methods.
And it's supposed to work for classes?
Yes. It's all in the spec: Class Properties The .tupleof property returns an ExpressionTuple of all the fields in the class, excluding the hidden fields and the fields in the base class.
Ah. Then it's not supposed to generate an error: Error: type Foo is not an expression For reference, here's the code, and I think it's not my error: class Foo { // Comment the following line to eliminate the error: // Error: type Foo is not an expression int i; } foreach (blah; Foo.tupleof) { writefln("%s", blah.stringof); } // or: auto a = Foo.tupleof[0];
Foo is a type. So Foo.tupleof would be a type tuple (if anything -- I'm not sure that works, though it does for structs). You probably need auto a = (new Foo).tupleof[0]; --bb
Nov 29 2007
parent Christopher Wright <dhasenan gmail.com> writes:
Bill Baxter wrote:
 Christopher Wright wrote:
 Jarrett Billingsley wrote:
 "Christopher Wright" <dhasenan gmail.com> wrote in message 
 news:finqpt$lnj$2 digitalmars.com...
 Jarrett Billingsley wrote:
 "Christopher Wright" <dhasenan gmail.com> wrote in message 
 news:fink7k$6ph$1 digitalmars.com...

 But tupleof fails if you give it a class that has fields (methods 
 are fine, but data fields aren't). I'm pretty sure this is a bug; 
 can anyone else comment on it?
tupleof is supposed to give you a tuple of fields. It will never give methods.
And it's supposed to work for classes?
Yes. It's all in the spec: Class Properties The .tupleof property returns an ExpressionTuple of all the fields in the class, excluding the hidden fields and the fields in the base class.
Ah. Then it's not supposed to generate an error: Error: type Foo is not an expression For reference, here's the code, and I think it's not my error: class Foo { // Comment the following line to eliminate the error: // Error: type Foo is not an expression int i; } foreach (blah; Foo.tupleof) { writefln("%s", blah.stringof); } // or: auto a = Foo.tupleof[0];
Foo is a type. So Foo.tupleof would be a type tuple (if anything -- I'm not sure that works, though it does for structs). You probably need auto a = (new Foo).tupleof[0]; --bb
If you want to use it as a type, though, you have to do typeof(Foo.tupleof[0]). But you still can't do (Foo.tupleof[0]).stringof ("Error: Foo.tupleof is used as a type").
Nov 29 2007