May 03, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 2015-05-03 06:20, Andrei Alexandrescu wrote: > Is this a common thing people wanna do? Put in Phobos? Yes, I would think so. Although, I would prefer a regular template mixin and taking the member as an alias parameter instead of a string, if possible. -- /Jacob Carlborg |
May 03, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On 5/3/15 12:18 AM, Meta wrote: > On Sunday, 3 May 2015 at 05:49:52 UTC, Andrei Alexandrescu wrote: >> On 5/2/15 10:00 PM, Meta wrote: >>> It seems like it'd be a lot cheaper and cleaner to just be able to alias >>> the parent method. >> >> Yeh, that's the first solution that comes to mind. alias doesn't work >> here but of course we could change the language. >> >>> Also, it could probably be made a bit simpler with >>> opDispatch. >> >> I'd have to see the code, but my intuition is that things could get >> quite a bit more hairy. >> >> >> Andrei > > IMO, using __traits and opDispatch is a fair bit cleaner, and I prefer > the syntax of a mixin template to regular mixin. > > http://dpaste.dzfl.pl/d60498246577 You're right, that is lovely! I've improved it as follows: mixin template forwardToMember(alias member, methods...) { import std.algorithm : among; import std.traits : ParameterTypeTuple; template opDispatch(string sym) if ((methods.length == 0 || sym.among(methods))) { auto ref opDispatch( ParameterTypeTuple!(__traits(getMember, member, sym)) args) { return __traits(getMember, member, sym)(args); } } } So now ref returns are preserved and the mixin is self-contained (doesn't require imports from the outside). Compared to my solution, this has the advantage that if the child defines a method, it will take precedence over the formatted one. So that allowed me to add a feature: if no methods are specified, all are forwarded. There are a couple of ways in which this could and should be improved, most notably overloads control. Even as is it's pretty darn awesome, Meta could you please make it into a pull request? I think it should go in std.functional. Andrei |
May 03, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sunday, 3 May 2015 at 18:54:45 UTC, Andrei Alexandrescu wrote:
> I think it should go in std.functional.
All similar utilities are currently in std.typecons
|
May 03, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On 5/3/15 12:04 PM, Dicebot wrote:
> On Sunday, 3 May 2015 at 18:54:45 UTC, Andrei Alexandrescu wrote:
>> I think it should go in std.functional.
>
> All similar utilities are currently in std.typecons
worksforme -- Andrei
|
May 03, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 5/3/15 11:54 AM, Andrei Alexandrescu wrote:
> On 5/3/15 12:18 AM, Meta wrote:
>> On Sunday, 3 May 2015 at 05:49:52 UTC, Andrei Alexandrescu wrote:
>>> On 5/2/15 10:00 PM, Meta wrote:
>>>> It seems like it'd be a lot cheaper and cleaner to just be able to
>>>> alias
>>>> the parent method.
>>>
>>> Yeh, that's the first solution that comes to mind. alias doesn't work
>>> here but of course we could change the language.
>>>
>>>> Also, it could probably be made a bit simpler with
>>>> opDispatch.
>>>
>>> I'd have to see the code, but my intuition is that things could get
>>> quite a bit more hairy.
>>>
>>>
>>> Andrei
>>
>> IMO, using __traits and opDispatch is a fair bit cleaner, and I prefer
>> the syntax of a mixin template to regular mixin.
>>
>> http://dpaste.dzfl.pl/d60498246577
>
> You're right, that is lovely! I've improved it as follows:
>
> mixin template forwardToMember(alias member, methods...)
> {
> import std.algorithm : among;
> import std.traits : ParameterTypeTuple;
> template opDispatch(string sym)
> if ((methods.length == 0 || sym.among(methods)))
> {
> auto ref opDispatch(
> ParameterTypeTuple!(__traits(getMember, member, sym)) args)
> {
> return __traits(getMember, member, sym)(args);
> }
> }
> }
>
> So now ref returns are preserved and the mixin is self-contained
> (doesn't require imports from the outside).
>
> Compared to my solution, this has the advantage that if the child
> defines a method, it will take precedence over the formatted one. So
> that allowed me to add a feature: if no methods are specified, all are
> forwarded.
>
> There are a couple of ways in which this could and should be improved,
> most notably overloads control. Even as is it's pretty darn awesome,
> Meta could you please make it into a pull request? I think it should go
> in std.functional.
Take that back, the opDispatch-based solution has a fatal flaw: doesn't compose properly. For example, in std.allocator it's frequent that allocators stack on top of one another, so one forwards a method call to another one which in turn forwards to another.
With code generation this obviously works out of the box because the generated code is identical to what one would write by hand to achieve the same. But the opDispatch-based solution only works one level.
Andrei
|
May 03, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | OK, here's what I have now - two templates that are self contained and work well: The first uses opDispatch to dispatch to a member. The second is a simple string function that generates the appropriate code. As discussed the latter composes but the former doesn't. mixin template dispatchToMember(alias member, methods...) { import std.algorithm : among; import std.traits : ParameterTypeTuple; template opDispatch(string sym) if ((methods.length == 0 || sym.among(methods))) { auto ref opDispatch(ParameterTypeTuple!(__traits(getMember, member, sym)) args) { return __traits(getMember, member, sym)(args); } } } string forwardToMember(string member, string[] funs...) { string result = " import std.traits : hasMember, ParameterTypeTuple;\n"; foreach (fun; funs) { result ~= " static if (hasMember!(typeof("~member~"), `"~fun~"`)) auto "~fun~"(ParameterTypeTuple!(typeof("~member~"."~fun~")) args) { return "~member~"."~fun~"(args); }\n"; } return result; } Andrei |
May 03, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sunday, 3 May 2015 at 20:25:45 UTC, Andrei Alexandrescu wrote:
> OK, here's what I have now - two templates that are self contained and work well:
>
> The first uses opDispatch to dispatch to a member. The second is a simple string function that generates the appropriate code. As discussed the latter composes but the former doesn't.
I can't picture what you're talking about. Could you post an example?
|
May 03, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On 5/3/15 4:20 PM, Meta wrote:
> On Sunday, 3 May 2015 at 20:25:45 UTC, Andrei Alexandrescu wrote:
>> OK, here's what I have now - two templates that are self contained and
>> work well:
>>
>> The first uses opDispatch to dispatch to a member. The second is a
>> simple string function that generates the appropriate code. As
>> discussed the latter composes but the former doesn't.
>
> I can't picture what you're talking about. Could you post an example?
struct A
{
void fun(int);
}
struct B
{
A a;
mixin forwardToMember!(a, "fun");
}
struct C
{
B b;
mixin forwardToMember!(b, "fun");
}
Andrei
|
May 04, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Sunday, 3 May 2015 at 23:54:49 UTC, Andrei Alexandrescu wrote: > On 5/3/15 4:20 PM, Meta wrote: >> On Sunday, 3 May 2015 at 20:25:45 UTC, Andrei Alexandrescu wrote: >>> OK, here's what I have now - two templates that are self contained and >>> work well: >>> >>> The first uses opDispatch to dispatch to a member. The second is a >>> simple string function that generates the appropriate code. As >>> discussed the latter composes but the former doesn't. >> >> I can't picture what you're talking about. Could you post an example? > > struct A > { > void fun(int); > } > > struct B > { > A a; > mixin forwardToMember!(a, "fun"); > } > > struct C > { > B b; > mixin forwardToMember!(b, "fun"); > } > > > Andrei I still don't get it. Your example works with both dispatchToMember and forwardToMember. What is the difference between these two exactly? auto opDispatch(string sym: foo)(ParemeterTypeTuple!(/*etc*/) args) { return parent.foo(args); } //Automatically generated auto foo(ParameterTypeTuple!(/*etc*/) args) { return parent.foo(args); } |
May 04, 2015 Re: The most awesome "forward to member" solution? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On 5/3/15 5:29 PM, Meta wrote:
> On Sunday, 3 May 2015 at 23:54:49 UTC, Andrei Alexandrescu wrote:
>> On 5/3/15 4:20 PM, Meta wrote:
>>> On Sunday, 3 May 2015 at 20:25:45 UTC, Andrei Alexandrescu wrote:
>>>> OK, here's what I have now - two templates that are self contained and
>>>> work well:
>>>>
>>>> The first uses opDispatch to dispatch to a member. The second is a
>>>> simple string function that generates the appropriate code. As
>>>> discussed the latter composes but the former doesn't.
>>>
>>> I can't picture what you're talking about. Could you post an example?
>>
>> struct A
>> {
>> void fun(int);
>> }
>>
>> struct B
>> {
>> A a;
>> mixin forwardToMember!(a, "fun");
>> }
>>
>> struct C
>> {
>> B b;
>> mixin forwardToMember!(b, "fun");
>> }
>>
>>
>> Andrei
>
> I still don't get it. Your example works with both dispatchToMember and
> forwardToMember. What is the difference between these two exactly?
>
> auto opDispatch(string sym: foo)(ParemeterTypeTuple!(/*etc*/) args)
> {
> return parent.foo(args);
> }
>
> //Automatically generated
> auto foo(ParameterTypeTuple!(/*etc*/) args)
> {
> return parent.foo(args);
> }
Hmm, I didn't try it assuming it won't work (thought __traits(getMember, member, sym) would fail with opDispatch). Tried it just now, it does work like a charm. Thanks!
Andrei
|
Copyright © 1999-2021 by the D Language Foundation