www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to obtain certain traits of delegates returned by functions in

reply "DoctorCaptain" <garble harble.com> writes:
My question is hopefully short and straightforward to answer, but 
it's also a two-parter.

I am working on a template that generates a function that 
implements an algorithm using several helper functions that are 
provided to the template by the user. I would like to add 
constraints to the template to restrict what functions the user 
can attempt to instantiate the template with, as the algorithm 
implemented by a function in the template has specific 
requirements. One of the functions required by the template needs 
to return a delegate so that it can be used as a generator of 
sorts. In any case. I have the ability to check the return type, 
arity, and parameter list of a function in the constraints of the 
template, and I can also check the return type of the delegate 
returned by the function.

So, first, how do I check the arity of and retrieve a parameter 
type tuple of the delegate returned by the function? Hopefully 
the example code in the following dpaste will fully illustrate my 
question:

http://dpaste.dzfl.pl/ef1a970f

Second, can I get the level of thoroughness I am going for in 
these constraints checks with fewer actual checks? As in, is 
there a more straightforward way to do these checks without 
sacrificing any of them?

Thank you for any and all insight!
Dec 14 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 12/14/2013 11:53 AM, DoctorCaptain wrote:> My question is hopefully 
short and straightforward to answer, but it's
 also a two-parter.

 I am working on a template that generates a function that implements an
 algorithm using several helper functions that are provided to the
 template by the user. I would like to add constraints to the template to
 restrict what functions the user can attempt to instantiate the template
 with, as the algorithm implemented by a function in the template has
 specific requirements. One of the functions required by the template
 needs to return a delegate so that it can be used as a generator of
 sorts. In any case. I have the ability to check the return type, arity,
 and parameter list of a function in the constraints of the template, and
 I can also check the return type of the delegate returned by the 
function.
 So, first, how do I check the arity of and retrieve a parameter type
 tuple of the delegate returned by the function? Hopefully the example
 code in the following dpaste will fully illustrate my question:

 http://dpaste.dzfl.pl/ef1a970f
Most uses of the 'is expression' allows using a specifier to name the entity that matched. So, inserting ReturnedDelegate in your '== delegate' line gives the name ReturnedDelegate to the delegate. That name can be used further: template exT(T, alias nextGen) if ( // Ensure nextGen is a callable entity isCallable!nextGen == true // Ensure nextGen returns a delegate && is(ReturnType!nextGen ReturnedDelegate == delegate) // <-- // Ensure nextGen takes one argument && arity!nextGen == 1 // Ensure that argument is of type T && is(ParameterTypeTuple!nextGen[0] == T) // Ensure the returned delegate returns type T && is(ReturnType!ReturnedDelegate == T) // Ensure the arity and parameter type of the delegate // && arity!ReturnedDelegate == 1 && ParameterTypeTuple!ReturnedDelegate.length == 1 // <-- && is(ParameterTypeTuple!ReturnedDelegate[0] == int) // <-- ) { // ... } However, since arity() takes an alias but ReturnedDelegate is a type, I could not make it work. So, I use the length of the parameter type tuple instead.
 Second, can I get the level of thoroughness I am going for in these
 constraints checks with fewer actual checks? As in, is there a more
 straightforward way to do these checks without sacrificing any of them?

 Thank you for any and all insight!
You can put all of those checks into a template and pass T and nextGen to it: template exT(T, alias nextGen) if SatisfiesMyConditions!(T, nextGen) { // ... } I haven't attempted writing it but it will be similar to the following syntax: template canFlyAndLand(T) { enum canFlyAndLand = is (typeof( { T object; object.prepare(); // should be preparable for flight object.fly(1); // should be flyable for a certain distance object.land(); // should be landable }())); } I've copied that example from under the "Named constraints" section at http://ddili.org/ders/d.en/templates_more.html Phobos implementation has many examples of that as well. Ali
Dec 14 2013
parent reply "DoctorCaptain" <garble harble.com> writes:
 Most uses of the 'is expression' allows using a specifier to 
 name the entity that matched. So, inserting ReturnedDelegate in 
 your '== delegate' line gives the name ReturnedDelegate to the 
 delegate.

 That name can be used further:

 template exT(T, alias nextGen)
     if (
         // Ensure nextGen is a callable entity
            isCallable!nextGen == true
         // Ensure nextGen returns a delegate
         && is(ReturnType!nextGen ReturnedDelegate == delegate) 
 // <--
         // Ensure nextGen takes one argument
         && arity!nextGen == 1
         // Ensure that argument is of type T
         && is(ParameterTypeTuple!nextGen[0] == T)
         // Ensure the returned delegate returns type T
         && is(ReturnType!ReturnedDelegate == T)
         // Ensure the arity and parameter type of the delegate
 		// && arity!ReturnedDelegate == 1
         && ParameterTypeTuple!ReturnedDelegate.length == 1 // 
 <--
         && is(ParameterTypeTuple!ReturnedDelegate[0] == int) // 
 <--
         )
 {
     // ...
 }

 However, since arity() takes an alias but ReturnedDelegate is a 
 type, I could not make it work. So, I use the length of the 
 parameter type tuple instead.

 You can put all of those checks into a template and pass T and 
 nextGen to it:

 template exT(T, alias nextGen)
     if SatisfiesMyConditions!(T, nextGen)
 {
     // ...
 }

 I haven't attempted writing it but it will be similar to the 
 following syntax:

 template canFlyAndLand(T)
 {
     enum canFlyAndLand = is (typeof(
     {
         T object;
         object.prepare();  // should be preparable for flight
         object.fly(1);     // should be flyable for a certain 
 distance
         object.land();     // should be landable
     }()));
 }

 I've copied that example from under the "Named constraints" 
 section at

   http://ddili.org/ders/d.en/templates_more.html

 Phobos implementation has many examples of that as well.

 Ali
Thank you! This is excellent, and I'll make great use of your suggestions.
 I would think you can check the delegate signature directly 
 without decomposing it. Something like this:

 is(ReturnType!nextGen == T delegate (int))
This is a very concise way to do what I want to do, but this check cares about other attributes of the function/delegate, i.e. if the function or delegate is designated as pure or nothrow and those don't show up in the check, it will fail. As in: auto nextGen() { T genFunc(int x) nothrow { return 0; } return &genFunc; } genFunc will fail the is() check because the is check cares whether the delegate is nothrow or not. Since I want folks to be able to use my algorithm without caring about the implementation details, I need to provide constraints for the parameter lists and return types of their functions, but no constraints on whatever attributes they want to slap onto their functions. I will keep this in my toolbox, but I'll have to take the more long-winded approach this time around. Thank you both!
Dec 14 2013
next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
I have 3 comments (if you're still reading this thread :) )

First, you could let nextGen determine the return type. Since the
template know that nextGen returns an int delegate(int), there is no
need for the user to provide the 'int' parameter.

So user code could become:

void main(string[] argv)
{
    auto exFunc = &exT!(nextGen).exFunc; // <- here
    exFunc();
}

Second, you could have exT return (become) the function itself, saving
you the trouble to call it with exT!(...).exFunc
In that case, exT could be a template function.

Third, you can also use it directly, like this:

    // First call:
    exT!(nextGen)();

If you still want to name it other wise, you can use and alias:


    // Second call:
    alias myFunc1 = exT!(nextGen);
    myFunc1();


Or use a function pointer, as in your initial code:

    // Third call:
    auto myFunc2 = &exT!(nextGen);
    myFunc2();

Which gives us shorter developer and user code. See here.

http://dpaste.dzfl.pl/63a220cf
Dec 14 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-12-14 23:38, DoctorCaptain wrote:

 This is a very concise way to do what I want to do, but this check cares
 about other attributes of the function/delegate, i.e. if the function or
 delegate is designated as pure or nothrow and those don't show up in the
 check, it will fail. As in:

 auto nextGen()
 {
      T genFunc(int x) nothrow
      {
          return 0;
      }
      return &genFunc;
 }

 genFunc will fail the is() check because the is check cares whether the
 delegate is nothrow or not. Since I want folks to be able to use my
 algorithm without caring about the implementation details, I need to
 provide constraints for the parameter lists and return types of their
 functions, but no constraints on whatever attributes they want to slap
 onto their functions. I will keep this in my toolbox, but I'll have to
 take the more long-winded approach this time around.
Hmm, there might be a way to strip all the attributes of a function. -- /Jacob Carlborg
Dec 15 2013
parent reply "TheFlyingFiddle" <kurtyan student.chalmers.se> writes:
On Sunday, 15 December 2013 at 10:44:38 UTC, Jacob Carlborg wrote:
 Hmm, there might be a way to strip all the attributes of a 
 function.
template strip(T) if(is(T == delegate)) { alias stripped = ReturnType!T delegate(ParameterTypeTuple!T); } template strip(T) if(is(T == function)) { alias stripped = ReturnType!T function(ParameterTypeTuple!T); } unittest { alias a = void delegate(int) nothrow pure const; alias b = void delegate(int); static assert(is(stripped!a == stripped!b)); } This should do the trick.
Dec 15 2013
parent "TheFlyingFiddle" <kurtyan student.chalmers.se> writes:
 template strip(T) if(is(T == delegate))
Typo should be stripped.
Dec 15 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-12-14 20:53, DoctorCaptain wrote:

 Second, can I get the level of thoroughness I am going for in these
 constraints checks with fewer actual checks? As in, is there a more
 straightforward way to do these checks without sacrificing any of them?

 Thank you for any and all insight!
I would think you can check the delegate signature directly without decomposing it. Something like this: is(ReturnType!nextGen == T delegate (int)) -- /Jacob Carlborg
Dec 14 2013