www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Copy parameters from function passed as an alias

reply bauss <jj_1337 live.dk> writes:
Is there a way to copy parameters from a passed function as an 
alias.

Ex:

void foo(alias fun)(...);

where ... should be the parameters of fun.

Of course std.traits.Parameters works like:

void foo(alias fun)(Parameters!fun);

But the catch is that you don't get the identifiers.

So what is the next alternative?

Okay let's just make it a template then ..

template foo(alias fun)
{
   static const parameterTypes = 
Parameters!(fun).stringof[1..$-1].split(", ");
   static const parameterNames = [ParameterIdentifierTuple!(fun)];

   private string generateParameters()
   {
     string[] s = [];

     static foreach (i; 0 .. parameterTypes.length)
     {
       s ~= parameterType[i] ~ " " ~ parameterNames[i];
     }

     return s.join(",");
   }

   void foo(mixin(generateParameters()))
   {
     ...
   }
}

Hmmm well this doesn't work because mixin cannot be placed there.

So the next alternative is a long ugly mixin like:

template foo(alias fun)
{
   static const parameterTypes = 
Parameters!(fun).stringof[1..$-1].split(", ");
   static const parameterNames = [ParameterIdentifierTuple!(fun)];

   private string generateParameters()
   {
     string[] s = [];

     static foreach (i; 0 .. parameterTypes.length)
     {
       s ~= parameterTypes[i] ~ " " ~ parameterNames[i];
     }

     return s.join(",");
   }

   mixin("void foo(" ~ generateParameters() ~ ") {" ~ q{
     ...
   } ~ "}");
}

There must be a better way to do this.

Ex.

class Foo
{
   void a(int b, int c) { }
}

When passed to foo like "foo!(Foo.a)" should produce:

void foo(int b, int c)
{
   ...
}
Oct 09 2018
parent reply Kagamin <spam here.lot> writes:
How do you want to use parameter names of an arbitrary function?
Oct 10 2018
parent reply bauss <jj_1337 live.dk> writes:
On Wednesday, 10 October 2018 at 08:16:11 UTC, Kagamin wrote:
 How do you want to use parameter names of an arbitrary function?
What I want to do is pass a function to a template and that template creates a function with the same parameters as the function passed to it, if it wasn't clear. I can already do that if you see my examples, BUT it's not pretty.
Oct 10 2018
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 10 October 2018 at 12:10:06 UTC, bauss wrote:
 On Wednesday, 10 October 2018 at 08:16:11 UTC, Kagamin wrote:
 How do you want to use parameter names of an arbitrary 
 function?
What I want to do is pass a function to a template and that template creates a function with the same parameters as the function passed to it, if it wasn't clear. I can already do that if you see my examples, BUT it's not pretty.
I suppose the question is, why is your first example inadequate? In other words, why is it important that the parameters of the generated function have the same names as the original parameters?
Oct 10 2018
parent reply bauss <jj_1337 live.dk> writes:
On Wednesday, 10 October 2018 at 18:15:52 UTC, Paul Backus wrote:
 On Wednesday, 10 October 2018 at 12:10:06 UTC, bauss wrote:
 On Wednesday, 10 October 2018 at 08:16:11 UTC, Kagamin wrote:
 How do you want to use parameter names of an arbitrary 
 function?
What I want to do is pass a function to a template and that template creates a function with the same parameters as the function passed to it, if it wasn't clear. I can already do that if you see my examples, BUT it's not pretty.
I suppose the question is, why is your first example inadequate? In other words, why is it important that the parameters of the generated function have the same names as the original parameters?
Because I'm constructing something from the parameters. To give the real world example. I'm converting a function into a soap envelope which means the identifiers must be the same because the parameter names passed in the soap envelope must have the same names. Basically what I wanted was something like: SoapEnvelope toEnvelope(alias fun)(...); // where ... is the parameters of fun The toEnvelope function then constructs the envelope based on the function name and the parameters. Within the "fun" function the soap envelope is constructed at compile-time and then simply sends the envelope to the soap client. It's a bit more complex than that, but it should give you the idea. If the parameter names do not match the given function then the parameters passed to the soap envelope's body will be invalid and thus of course rejected by the web service. I have it working with the ugly example I've given using the template and the mixin, but it's no ideal because first of all it's not pretty, it's difficuly to debug because well you can't place any breakpoints within the function simply because the function body is a string and at last it's just everything but easy to maintain. If there was something like "CopyParameters!fun" then it'd be so much easier, but unfortunately there are only two choices here. "Parameters!fun" will just give you the parameter types and "ParameterIdentifierTuple!fun" will give you the parameter identifiers. The problem is that when you want to construct the parameters you can't really combine both of them without the last example I've given and that's the problem. The second example I gave would be okay, because you'd only have to maintain the parameter mixin, but the first example would be best because there are no mixins involved at all then. The last example is pretty much a last resort and pretty much undesirable.
Oct 10 2018
next sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Thursday, 11 October 2018 at 06:30:01 UTC, bauss wrote:
 Because I'm constructing something from the parameters.

 To give the real world example.

 I'm converting a function into a soap envelope which means the 
 identifiers must be the same because the parameter names passed 
 in the soap envelope must have the same names.
Filed an enhancement request: https://issues.dlang.org/show_bug.cgi?id=19299 For now, I believe the giant mixin is your only option, if you absolutely need the parameters to have the same names. If having local variables with the same names is ok, this should do it: import std.stdio; import std.traits : ParameterIdentifierTuple, Parameters; auto fun(alias fn)(Parameters!fn args) { mixin(copyParameters!fn); writeln(a); } auto copyParameters(alias fn)() { import std.conv : to; string result; static foreach (i, e; ParameterIdentifierTuple!fn) { result ~= "auto "~e~" = args["~i.to!string~"];\n"; } return result; } void gun(int a) {} unittest { fun!(gun)(3); } Now, is this the only way to inform the soap factory of your parameter names? Could you instead pass them more explicitly? -- Simen
Oct 11 2018
parent bauss <jj_1337 live.dk> writes:
On Thursday, 11 October 2018 at 07:44:04 UTC, Simen Kjærås wrote:
 Now, is this the only way to inform the soap factory of your 
 parameter names? Could you instead pass them more explicitly?
The variable example is actually a good alternative. I like it. To answer your question however, yes because all functionality is converted from a WSDL file to D types and the D types correspond to the soap service and its functions. It should be as minimal as possible because the generated module should not be a module that should get modified since it’s autogenerated. I mean it’s possible to manually construct the envelopes but the point is to automate the whole process so all you gotta do is write regular D code that seems to call regular D functions even though those functions are actually soap operations.
Oct 11 2018
prev sibling parent Kagamin <spam here.lot> writes:
On Thursday, 11 October 2018 at 06:30:01 UTC, bauss wrote:
 To give the real world example.

 I'm converting a function into a soap envelope which means the 
 identifiers must be the same because the parameter names passed 
 in the soap envelope must have the same names.

 Basically what I wanted was something like:

 SoapEnvelope toEnvelope(alias fun)(...); // where ... is the 
 parameters of fun

 The toEnvelope function then constructs the envelope based on 
 the function name and the parameters.

 Within the "fun" function the soap envelope is constructed at 
 compile-time and then simply sends the envelope to the soap 
 client.
SoapEnvelope toEnvelope(alias fun)(Parameters!fun args) { SoapEnvelope envelope; static foreach (i, name; ParameterIdentifierTuple!fun) { envelope.addField(name, args[i].toString()); } }
Oct 11 2018