Check for presence of function
What's the cool/idiomatic D way to test at compile time if a struct has a member function with a particular signature? Along the lines of: struct Unrelated { ... } template isSomething(T) { enum bool isSomething = is(typeof( (inout int = 0) { T???; // has a function void doSomething(Unrelated* up); // etc })); } struct Thingie { ... } static assert(isSomething!(Thingie)); Thanks Steve
Re: Check for presence of function
On Sun, Mar 23, 2014 at 1:40 PM, Steve Teale steve.te...@britseyeview.com wrote: What's the cool/idiomatic D way to test at compile time if a struct has a member function with a particular signature? Along the lines of: struct Unrelated { ... } template isSomething(T) { enum bool isSomething = is(typeof( (inout int = 0) { T???; // has a function void doSomething(Unrelated* up); // etc })); } struct Thingie { ... } static assert(isSomething!(Thingie)); You can use __traits(compiles, /* some code */), like this: struct Unrelated {} template isSomething(T) { enum bool isSomething = __traits(compiles, { Unrelated* up; T.init.doSomething(up); } ); } struct Thingie { void doSomething(Unrelated* up) {} } void main() { pragma(msg, isSomething!Thingie); // true pragma(msg, isSomething!Unrelated); // false pragma(msg, isSomething!int); // false }
Re: Check for presence of function
template isSomething(T) { enum isSomething = is(typeof(__traits(getMember, T, doSomething)) == function) is(typeof(__traits(getMember, T, doSomething)) : void function(Unrelated*)); }
Re: Check for presence of function
Ideally, the alias part of the grammar could be extended and isSomething simplified as: alias isSomething(T) = __traits(compiles, { Unrelated* up; T.init.doSomething(up); } ); But this is not accepted by the grammar right now, because of __traits()
Re: Check for presence of function
On Sunday, 23 March 2014 at 12:57:36 UTC, Philippe Sigaud wrote: But this is not accepted by the grammar right now, because of __traits() That's easy enough to work around with an alias helper: alias helper(alias T) = T; alias isSomething(T) = alias!(__traits(compiles, { Unrelated* up; T.init.doSomething(up); } ));
Re: Check for presence of function
On Sunday, 23 March 2014 at 13:00:09 UTC, Adam D. Ruppe wrote: alias isSomething(T) = alias!(__traits(compiles, oops that should say helper! not alias!
Re: Check for presence of function
On Sunday, 23 March 2014 at 12:53:39 UTC, Dicebot wrote: template isSomething(T) { enum isSomething = is(typeof(__traits(getMember, T, doSomething)) == function) is(typeof(__traits(getMember, T, doSomething)) : void function(Unrelated*)); } That won't necessarily work in the presence of overloaded functions since getMember only gets one of them. You could though do this: template isSomething(T) { bool checker() { foreach(overload; __traits(getOverloads, T, doSomething)) static if(is(typeof(overload) == void function(Unrelated*))) return true; return false; } enum isSomething = checker(); } getOverloads returns an empty tuple for non-functions so you don't even have to check that ahead of time.
Re: Check for presence of function
On Sunday, 23 March 2014 at 13:03:07 UTC, Adam D. Ruppe wrote: That won't necessarily work in the presence of overloaded functions since getMember only gets one of them. Yeah, forgot to add this part, will make end result a bit less pretty indeed. Updated version with overloads will be more reliable than proposed duck-typing version as it won't false trigger in presence of alias this or opDispatch. Though Steve may actually want it to trigger, I don't know.
Re: Check for presence of function
On 3/23/14, Philippe Sigaud philippe.sig...@gmail.com wrote: But this is not accepted by the grammar right now, because of __traits() Pretty sure it's because you're using 'alias' instead of 'enum'. This works: - enum isSomething(T) = __traits(compiles, { int up; T.init.doSomething(up); } ); void main() { static struct S { void doSomething(int); } static struct X { void doSomething(string); } static assert(isSomething!S); static assert(!isSomething!X); } -
Re: Check for presence of function
On Sun, Mar 23, 2014 at 2:50 PM, Andrej Mitrovic andrej.mitrov...@gmail.com wrote: Pretty sure it's because you're using 'alias' instead of 'enum'. This works: Oww! For years, D told me I couldn't use __traits in an easy way like this. I'll have to teach me out of it, and use enum :-) Damn, but using enum is quite natural too. Thanks Andrej. Now, if only __traits could be beautified somewhat... I mean: everyone is using it, it's time to make it more palatable.
Re: Check for presence of function
On Sunday, 23 March 2014 at 13:23:58 UTC, Dicebot wrote: On Sunday, 23 March 2014 at 13:03:07 UTC, Adam D. Ruppe wrote: That won't necessarily work in the presence of overloaded functions since getMember only gets one of them. Yeah, forgot to add this part, will make end result a bit less pretty indeed. Updated version with overloads will be more reliable than proposed duck-typing version as it won't false trigger in presence of alias this or opDispatch. Though Steve may actually want it to trigger, I don't know. DB, In my particular question, I would not have wanted, or cared if alias this was triggered, but that was a narrow view. My primary point is that there should be something in the wiki to help old-fashioned programmers like me to change from an OOP style that is not 100% necessary, to a struct based style that should be quicker, but that allows the compiler to help me, or other contributors to the same project, to write add-on components that are at least checked at compile time. So what I'm after really, is how do you do interfaces outside of OOP. Std.range does that sort of thing in what seem to me to be very simple cases, but there is a lot of scope for different scenarios. Thanks for your answer Steve
Re: Check for presence of function
On 3/23/14, Philippe Sigaud philippe.sig...@gmail.com wrote: Now, if only __traits could be beautified somewhat... I mean: everyone is using it, it's time to make it more palatable. That's what std.traits is for, to hide the __traits and is() uglyness.