October 03, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On Monday, October 03, 2016 08:38:22 Jonathan M Davis via Digitalmars-d wrote: > On Monday, October 03, 2016 23:19:19 Manu via Digitalmars-d wrote: > > Fill in the blank... > > I'm having a really hard time with this. I've made it work with a > > mountain of code, and I want to see what others come up with... > > It's certainly possible that this misses something, but it passes all of your test cases: > > template isStaticMember(T, string member) > { > static if(!__traits(hasMember, T, member)) > enum bool isStaticMember = false; > else > { > import std.meta : AliasSeq; > import std.traits : FunctionTypeOf; > alias sym = AliasSeq!(__traits(getMember, T, member))[0]; > static if(__traits(isStaticFunction, sym)) > enum bool isStaticMember = true; > else static if(is(FunctionTypeOf!sym == function) && > is(FunctionTypeOf!(typeof(&sym)) == function)) > { > enum bool isStaticMember = false; > } > else > { > enum bool isStaticMember = !__traits(compiles, sym.offsetof) && > !is(sym == enum) && > !is(sym == class) && > !is(sym == struct) && > __traits(compiles, &sym); > } > } > } Actually, it can be reduced even further: template isStaticMember(T, string member) { static if (!__traits(hasMember, T, member)) enum bool isStaticMember = false; else { import std.meta : AliasSeq; import std.traits : FunctionTypeOf; alias sym = AliasSeq!(__traits(getMember, T, member))[0]; static if (__traits(isStaticFunction, sym)) enum bool isStaticMember = true; else static if (is(FunctionTypeOf!sym == function) && is(FunctionTypeOf!(typeof(&sym)) == function)) { enum bool isStaticMember = false; } else { enum bool isStaticMember = !__traits(compiles, sym.offsetof) && __traits(compiles, &sym); } } } Checking for the address makes it unnecessary to check for enums, classes, or structs. - Jonathan M Davis |
October 03, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On Monday, October 03, 2016 11:13:52 Jonathan M Davis via Digitalmars-d wrote: > template isStaticMember(T, string member) > { > static if (!__traits(hasMember, T, member)) > enum bool isStaticMember = false; > else > { > import std.meta : AliasSeq; > import std.traits : FunctionTypeOf; > alias sym = AliasSeq!(__traits(getMember, T, member))[0]; > > static if (__traits(isStaticFunction, sym)) > enum bool isStaticMember = true; > else static if (is(FunctionTypeOf!sym == function) && > is(FunctionTypeOf!(typeof(&sym)) == function)) > { > enum bool isStaticMember = false; > } > else > { > enum bool isStaticMember = !__traits(compiles, sym.offsetof) && > __traits(compiles, &sym); > } > } > } Well, since I took the time to write it, I created a PR for it: https://github.com/dlang/phobos/pull/4834 So, if anyone sees problems with my implementation, go poke holes in it. - Jonathan M Davis |
October 04, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On 4 October 2016 at 05:01, Jonathan M Davis via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Monday, October 03, 2016 11:13:52 Jonathan M Davis via Digitalmars-d wrote:
>> template isStaticMember(T, string member)
>> {
>> static if (!__traits(hasMember, T, member))
>> enum bool isStaticMember = false;
>> else
>> {
>> import std.meta : AliasSeq;
>> import std.traits : FunctionTypeOf;
>> alias sym = AliasSeq!(__traits(getMember, T, member))[0];
>>
>> static if (__traits(isStaticFunction, sym))
>> enum bool isStaticMember = true;
>> else static if (is(FunctionTypeOf!sym == function) &&
>> is(FunctionTypeOf!(typeof(&sym)) == function))
>> {
>> enum bool isStaticMember = false;
>> }
>> else
>> {
>> enum bool isStaticMember = !__traits(compiles, sym.offsetof) &&
>> __traits(compiles, &sym);
>> }
>> }
>> }
>
> Well, since I took the time to write it, I created a PR for it:
>
> https://github.com/dlang/phobos/pull/4834
>
> So, if anyone sees problems with my implementation, go poke holes in it.
>
> - Jonathan M Davis
>
I'm feeling John's solution is a little bit simpler. But nice work, thanks!
|
October 03, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On Tuesday, October 04, 2016 11:13:36 Manu via Digitalmars-d wrote:
> I'm feeling John's solution is a little bit simpler. But nice work, thanks!
So, it is. LOL. I'd actually glanced over that post while I was in the middle of getting my version to work, and I read it too quickly, because I understood that it had just solved the property problem and that it didn't work for all cases. I'll have to update my PR. Though his code does make the mistake of doing
mixin(`alias mem = T.` ~ member ~ `;`);
rather than doing something like
alias mem = AliasSeq!(__traits(getMember, T, member))[0];
which means that there are some cases where it won't work properly. The core logic is simpler though, which is definitely a plus.
- Jonathan M Davis
|
October 04, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On 4 October 2016 at 12:30, Jonathan M Davis via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Tuesday, October 04, 2016 11:13:36 Manu via Digitalmars-d wrote:
>> I'm feeling John's solution is a little bit simpler. But nice work, thanks!
>
> So, it is. LOL. I'd actually glanced over that post while I was in the middle of getting my version to work, and I read it too quickly, because I understood that it had just solved the property problem and that it didn't work for all cases. I'll have to update my PR. Though his code does make the mistake of doing
>
> mixin(`alias mem = T.` ~ member ~ `;`);
>
> rather than doing something like
>
> alias mem = AliasSeq!(__traits(getMember, T, member))[0];
>
> which means that there are some cases where it won't work properly. The core logic is simpler though, which is definitely a plus.
Make that change in your PR :)
I think the PR is important. It's not obvious how to do this, and it's
very useful. I was astonished it's not already there.
|
October 03, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On Tuesday, October 04, 2016 14:24:59 Manu via Digitalmars-d wrote: > On 4 October 2016 at 12:30, Jonathan M Davis via Digitalmars-d > > <digitalmars-d@puremagic.com> wrote: > > On Tuesday, October 04, 2016 11:13:36 Manu via Digitalmars-d wrote: > >> I'm feeling John's solution is a little bit simpler. But nice work, thanks! > > > > So, it is. LOL. I'd actually glanced over that post while I was in the middle of getting my version to work, and I read it too quickly, because I understood that it had just solved the property problem and that it didn't work for all cases. I'll have to update my PR. Though his code does make the mistake of doing > > > > mixin(`alias mem = T.` ~ member ~ `;`); > > > > rather than doing something like > > > > alias mem = AliasSeq!(__traits(getMember, T, member))[0]; > > > > which means that there are some cases where it won't work properly. The core logic is simpler though, which is definitely a plus. > > Make that change in your PR :) I already updated it and was actually able to make it slightly simpler than John's example (as far as I can tell, FunctionTypeOf is only needed in the case where the address is taken). > I think the PR is important. It's not obvious how to do this, and it's very useful. I was astonished it's not already there. Yeah. I ran into a need for something similar recently, but my implementation at the time wasn't as thorough, since it just used offsetof to do the check (though in my case, I think that was enough). Getting it completely right is surprisingly difficult. I was also surprised that while we have quite a few __traits for functions, they're severely lacking for variables (e.g. I was looking for the variable equivalent of __traits(isStaticFunction, ...), and there is no such beast). For that matter, even testing whether something is a variable is surprisingly difficult. - Jonathan M Davis |
October 04, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On 4 October 2016 at 14:40, Jonathan M Davis via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> [...]
> For that matter, even testing whether something is a variable is
> surprisingly difficult.
True story! I've written that one before... I spent ages trying to get it right!
When people say D is highly complex, these are the reasons. There are
a lot of edges, and some arbitrary corners where things just don't
work.
*mutter mutter* storage class *mutter mutter*
|
October 04, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On 4 October 2016 at 14:40, Jonathan M Davis via Digitalmars-d <digitalmars-d@puremagic.com> wrote: > On Tuesday, October 04, 2016 14:24:59 Manu via Digitalmars-d wrote: >> On 4 October 2016 at 12:30, Jonathan M Davis via Digitalmars-d >> >> <digitalmars-d@puremagic.com> wrote: >> > On Tuesday, October 04, 2016 11:13:36 Manu via Digitalmars-d wrote: >> >> I'm feeling John's solution is a little bit simpler. But nice work, thanks! >> > >> > So, it is. LOL. I'd actually glanced over that post while I was in the middle of getting my version to work, and I read it too quickly, because I understood that it had just solved the property problem and that it didn't work for all cases. I'll have to update my PR. Though his code does make the mistake of doing >> > >> > mixin(`alias mem = T.` ~ member ~ `;`); >> > >> > rather than doing something like >> > >> > alias mem = AliasSeq!(__traits(getMember, T, member))[0]; >> > >> > which means that there are some cases where it won't work properly. The core logic is simpler though, which is definitely a plus. >> >> Make that change in your PR :) > > I already updated it and was actually able to make it slightly simpler than John's example (as far as I can tell, FunctionTypeOf is only needed in the case where the address is taken). > >> I think the PR is important. It's not obvious how to do this, and it's very useful. I was astonished it's not already there. > > Yeah. I ran into a need for something similar recently, but my implementation at the time wasn't as thorough, since it just used offsetof to do the check (though in my case, I think that was enough). Getting it completely right is surprisingly difficult. > > I was also surprised that while we have quite a few __traits for functions, they're severely lacking for variables (e.g. I was looking for the variable equivalent of __traits(isStaticFunction, ...), and there is no such beast). For that matter, even testing whether something is a variable is surprisingly difficult. > > - Jonathan M Davis While you're at it, might I suggest also adding std.traits.isProperty? Something like: template isProperty(T, string member) { import std.meta : AliasSeq; import std.traits : FunctionTypeOf; alias sym = AliasSeq!(__traits(getMember, T, member))[0]; enum isProperty = !is(typeof(sym) == function) && is(FunctionTypeOf!(typeof(&sym)) == function); } |
October 05, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On 4 October 2016 at 22:48, Manu <turkeyman@gmail.com> wrote:
> On 4 October 2016 at 14:40, Jonathan M Davis via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>> On Tuesday, October 04, 2016 14:24:59 Manu via Digitalmars-d wrote:
>>> On 4 October 2016 at 12:30, Jonathan M Davis via Digitalmars-d
>>>
>>> <digitalmars-d@puremagic.com> wrote:
>>> > On Tuesday, October 04, 2016 11:13:36 Manu via Digitalmars-d wrote:
>>> >> I'm feeling John's solution is a little bit simpler. But nice work, thanks!
>>> >
>>> > So, it is. LOL. I'd actually glanced over that post while I was in the middle of getting my version to work, and I read it too quickly, because I understood that it had just solved the property problem and that it didn't work for all cases. I'll have to update my PR. Though his code does make the mistake of doing
>>> >
>>> > mixin(`alias mem = T.` ~ member ~ `;`);
>>> >
>>> > rather than doing something like
>>> >
>>> > alias mem = AliasSeq!(__traits(getMember, T, member))[0];
>>> >
>>> > which means that there are some cases where it won't work properly. The core logic is simpler though, which is definitely a plus.
>>>
>>> Make that change in your PR :)
>>
>> I already updated it and was actually able to make it slightly simpler than John's example (as far as I can tell, FunctionTypeOf is only needed in the case where the address is taken).
>>
>>> I think the PR is important. It's not obvious how to do this, and it's very useful. I was astonished it's not already there.
>>
>> Yeah. I ran into a need for something similar recently, but my implementation at the time wasn't as thorough, since it just used offsetof to do the check (though in my case, I think that was enough). Getting it completely right is surprisingly difficult.
>>
>> I was also surprised that while we have quite a few __traits for functions, they're severely lacking for variables (e.g. I was looking for the variable equivalent of __traits(isStaticFunction, ...), and there is no such beast). For that matter, even testing whether something is a variable is surprisingly difficult.
>>
>> - Jonathan M Davis
>
> While you're at it, might I suggest also adding std.traits.isProperty?
> Something like:
>
> template isProperty(T, string member)
> {
> import std.meta : AliasSeq;
> import std.traits : FunctionTypeOf;
> alias sym = AliasSeq!(__traits(getMember, T, member))[0];
> enum isProperty = !is(typeof(sym) == function) &&
> is(FunctionTypeOf!(typeof(&sym)) == function);
> }
Why this AliasSeq business? That line is rather an abomination... why are all these horrible expressions popping up as recommendations nowadays?
|
October 04, 2016 Re: Challenge | ||||
---|---|---|---|---|
| ||||
On Wednesday, October 05, 2016 11:20:44 Manu via Digitalmars-d wrote: > > While you're at it, might I suggest also adding std.traits.isProperty? > > > > Something like: > > template isProperty(T, string member) > > { > > > > import std.meta : AliasSeq; > > import std.traits : FunctionTypeOf; > > alias sym = AliasSeq!(__traits(getMember, T, member))[0]; > > enum isProperty = !is(typeof(sym) == function) && > > > > is(FunctionTypeOf!(typeof(&sym)) == function); > > } > > Why this AliasSeq business? That line is rather an abomination... why are all these horrible expressions popping up as recommendations nowadays? The AliasSeq muck is there because for some reason you can't alias the result of __traits, so doing something like alias sym = __traits(getMember, T, member); isn't legal. So, this has nothing to do with a recommendation of best practice and everything to do with an annoying bug. https://issues.dlang.org/show_bug.cgi?id=7804 It _is_ however recommended to use __traits(getMember, T, member) over manually building it with strings with something like T.stringof ~ "." ~ member, because the string manipulation falls about in corner cases (e.g. it could result in a symbol conflict). It's just that then has the unfortunate side effect of requiring AliasSeq because of the bug. - Jonathan M Davis |
Copyright © 1999-2021 by the D Language Foundation