July 29, 2020
On Wednesday, 29 July 2020 at 10:38:29 UTC, Manu wrote:
> On Wed, Jul 29, 2020 at 9:40 AM Jean-Louis Leroy via
>> Guaranteed failure then? ;-)
>
> Yes.

What's wrong with my solution earlier in the thread?
July 29, 2020
On Wednesday, 29 July 2020 at 12:54:36 UTC, Adam D. Ruppe wrote:
> On Wednesday, 29 July 2020 at 10:38:29 UTC, Manu wrote:
>> On Wed, Jul 29, 2020 at 9:40 AM Jean-Louis Leroy via
>>> Guaranteed failure then? ;-)
>>
>> Yes.
>
> What's wrong with my solution earlier in the thread?

That it uses a string mixin :P

What Manu is arguing is that if parameter storage classes were instead proper type qualifiers, then one could trivially manipulate them with std.meta. And then supposedly there would be no need to string mixins at all.
I haven't spent the time to actually verify if that's the case here (perhaps the only need for using a string mixin is to generate variable names like Param1, Param2, ... ParamN) as is(X == __parameters) solves the issue with forwarding the whole parameter list (including storage classes), but in general, this doesn't scale if you need to do type manipulation with std.meta, as `alias RefInt = ref int` drops the `ref` storage class and this breaks everything like staticMap, Filter, etc.
July 29, 2020
On Wednesday, 29 July 2020 at 16:11:02 UTC, Petar Kirov [ZombineDev] wrote:
> On Wednesday, 29 July 2020 at 12:54:36 UTC, Adam D. Ruppe wrote:
>> On Wednesday, 29 July 2020 at 10:38:29 UTC, Manu wrote:
>>> On Wed, Jul 29, 2020 at 9:40 AM Jean-Louis Leroy via
>>>> Guaranteed failure then? ;-)
>>>
>>> Yes.
>>
>> What's wrong with my solution earlier in the thread?
>
> That it uses a string mixin :P
>
> What Manu is arguing is that if parameter storage classes were instead proper type qualifiers, then one could trivially manipulate them with std.meta. And then supposedly there would be no need to string mixins at all.

If we go back to the original problem, you still need a string mixin to inject the function name in two places.

As for Adam's solution, it solves a slightly different problem but I don't see why he uses a string mixin:

template forward(alias fun)
{
    import std.traits;
    @(__traits(getAttributes, fun)) auto ref forward(Parameters!fun args) {
        return fun(args);
    }
}

@(42) void myfun(int, ref double x, out string s);

pragma(msg, typeof(forward!myfun));
// void function(int _param_0, ref double _param_1, out string _param_2) @system
pragma(msg, __traits(getAttributes, forward!myfun));
// tuple(42)

Anyway, storage classes are not a difficulty, as long as you use the whole __parameters, or slice it (__parameters[0..1]), and refrain from indexing it (__parameters[0] loses storage classes). Strange beast...
July 29, 2020
On Wednesday, 29 July 2020 at 16:31:08 UTC, Jean-Louis Leroy wrote:
> As for Adam's solution, it solves a slightly different problem but I don't see why he uses a string mixin:

OK I see why Adam uses a string mixin: to generate identifiers to alias __parameters to. But that is not necessary. His complete example sans string mixins here: https://gist.github.com/jll63/d6575d2ec5318c355f164e529453db73
July 29, 2020
On Wednesday, 29 July 2020 at 16:11:02 UTC, Petar Kirov [ZombineDev] wrote:
> That it uses a string mixin :P

Not really - that string mixin is only there to work around a compiler bug leaking a name out of the scope

https://issues.dlang.org/show_bug.cgi?id=21078

Notice that the only thing actually mixed in is a random number to give a temporary variable a unique name.

It has nothing to do with storage classes or types or anything else.
July 29, 2020
On Wednesday, 29 July 2020 at 16:52:32 UTC, Jean-Louis Leroy wrote:
> OK I see why Adam uses a string mixin: to generate identifiers to alias __parameters to. But that is not necessary.

Yeah, that works too, but it introduces a template which I also try to avoid due to compiler memory management issues (the trivial mixin eats less dmd ram).
July 29, 2020
On Sunday, 26 July 2020 at 01:29:21 UTC, Andrei Alexandrescu wrote:
> This topic came about during beerconf (it was fun!): Write an idiomatic template `forward` that takes an alias `fun` and defines (generates) one overload for each overload of `fun`. Example:
>
> template forward(alias fun)
> {
>     ...
> }
>
> Now for this function:
>
> void myfun(int, ref double, out string);
> int myfun(in string, inout double);
>
> the instantiation would be (stylized):
>
> template forward!myfun
> {
>     void myfun(int a, ref double b, out string c)
>     {
>         return myfun(a, b, c);
>     }
>     int myfun(in string a, inout double b)
>     {
>         return myfun(a, b);
>     }
> }
>
> So the challenge is implementing forward() to do this.

I would be interested an actual use-cases for this?

Where would you use, forward? Where would it be the most pleasant solution, and others would be vastly inferior?
July 30, 2020
On Wed, Jul 29, 2020 at 10:35 PM Jean-Louis Leroy via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Wednesday, 29 July 2020 at 10:38:29 UTC, Manu wrote:
> > On Wed, Jul 29, 2020 at 9:40 AM Jean-Louis Leroy via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
> >
> >> On Tuesday, 28 July 2020 at 22:48:16 UTC, Manu wrote:
> >> > It is my opinion that if the solution involves a text-mixin, the author gets an instant FAIL.
> >>
> >> But:
> >>
> >> > The major hangup in this exercise is dealing with 'storage
> >> > class', which is
> >> > impossible because it's not part of the language, and
> >> > instantly
> >> > forces synthesising strings.
> >>
> >> Guaranteed failure then? ;-)
> >>
> >
> > Yes.
>
> This is a problem I spent a lot of time on while trying to support all the variations of functions in openmethods (and the problem is even harder because I need to alter the storage classes of a subset of the parameters).
>
> Doesn't this cut it?
>
> module challenge;
>
> template forward(alias fun)
> {
>      import std.format;
>      import std.traits;
>      enum name = __traits(identifier, fun);
>      static foreach (ovl; __traits(getOverloads, __traits(parent,
> fun), name)) {
>          mixin(q{
>                  auto ref %s(Parameters!ovl args) {
>                      return __traits(parent, fun).%s(args);
>                  }
>              }.format(name, name));
>      }
> }
>
> void myfun(int, ref double, out string);
>
> int myfun(in string, inout double);
>
> pragma(msg, typeof(__traits(getOverloads, forward!myfun,
> "myfun")[0]));
> pragma(msg, typeof(__traits(getOverloads, forward!myfun,
> "myfun")[1]));
>
> Output:
> void(int, ref double, out string)
> int(const(string), inout(double))
>
> This deals with storage classes all right.
>
> As for the string mixin, it would be nice to be able to do with it, or at least to narrow it to the function name, but in this respect D is more C than Lisp.
>
>
I mean... std.format in a forward macro? I find that embarrassing. Compile
times are important.  Of course, the usual casualties occur; debugging
steps through string mixins, etc.
Also, your solution doesn't perform any interesting transformation on
args... forwarding functions usually transform some argument(/s) in some
way, or inject additional arguments.
Hard and really lame to write any of the actual meat of the exercise inside
a string.

I'm not saying your solution is bad, just that the problem is bad, and it really sucks that this thread exists. I've been complaining about this since day-one. 'Storage class' is the problem as usual.


July 30, 2020
On Wed, Jul 29, 2020 at 10:55 PM Adam D. Ruppe via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Wednesday, 29 July 2020 at 10:38:29 UTC, Manu wrote:
> > On Wed, Jul 29, 2020 at 9:40 AM Jean-Louis Leroy via
> >> Guaranteed failure then? ;-)
> >
> > Yes.
>
> What's wrong with my solution earlier in the thread?
>

It's pretty good, except my experience is that __parameters works only in
the narrow case of a verbatim forward. I rarely find I need to implement a
verbatim forward; I almost always seem to encounter a forwarding pattern
when it is necessary to perform a parameter transformation of some kind, or
a parameter injection. You need to be able to handle the arguments and
iterate/manipulate them.
I find I'm typically synthesising wrappers or shim's, not verbatim
forwarding... which isn't strictly the topic of this thread, but it's a
100% related problem, and it seems to be what I actually need to do 95% of
the time rather than the challenge in the OP.


July 30, 2020
On Thursday, 30 July 2020 at 01:31:59 UTC, Manu wrote:

> Also, your solution doesn't perform any interesting transformation on
> args... forwarding functions usually transform some argument(/s) in some
> way, or inject additional arguments.

I struggled with that in openmethods where transformations do occur, and that's why I created this thingy: https://github.com/aliak00/bolts/blob/master/source/bolts/experimental/refraction.d, which allows you to create a function from a function, while manipulating its "aspects" in any way you want.

But yeah it's just a saner way of building a string mixin, and annoyingly, they are almost inevitable...just creating a function with anything but a fixed name requires a string mixin afaik..

Andrei's challenge and Adam's variation are among the simplest cases because the storage classes and function attributes can be inferred from the wrapped function. std.typecons.wrap, on the other hand, has to mess with function attributes.