Thread overview
Copy parameters from function passed as an alias
6 days ago
bauss
5 days ago
Kagamin
5 days ago
bauss
5 days ago
Paul Backus
4 days ago
bauss
4 days ago
Simen Kjærås
4 days ago
bauss
4 days ago
Kagamin
6 days ago
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)
{
  ...
}
5 days ago
How do you want to use parameter names of an arbitrary function?
5 days ago
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.
5 days ago
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?
4 days ago
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.
4 days ago
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
4 days ago
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.
4 days ago
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());
    }
}