Thread overview | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 21, 2006 static if check for array and AA | ||||
---|---|---|---|---|
| ||||
I'm fairly certain I've seen this come up before, but I can't seem to rediscover the thread. I'm trying to write a static if condition to check whether a certain type is an array, and another check for an associative array. The former proved to be moderately simple: bool isArray(T) () { static if (is(typeof(T.init[0])[] == T)) { return true; } else { return false; } } Note that this only checks for dynamic arrays. Associative arrays are harder. The above trick can't quite work as the type of the key can't be relied upon. It's easy enough to do the check using RTTI: bool isAA(T) () { TypeInfo t = typeid(T); if (cast(TypeInfo_AssociativeArray) t) { return true; } else { return false; } } But of course that is a runtime check, and this should really be a compile-time check. (Also, the various subclasses of TypeInfo are undocumented, so I'm not sure if it's a good idea to rely on them.) Anyone else have some template judo to share? -Kirk McDonald |
June 21, 2006 Re: static if check for array and AA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kirk McDonald | Kirk McDonald wrote:
> I'm fairly certain I've seen this come up before, but I can't seem to rediscover the thread.
>
> I'm trying to write a static if condition to check whether a certain type is an array, and another check for an associative array. The former proved to be moderately simple:
>
> bool isArray(T) () {
> static if (is(typeof(T.init[0])[] == T)) {
> return true;
> } else {
> return false;
> }
> }
>
> Note that this only checks for dynamic arrays.
>
> Associative arrays are harder. The above trick can't quite work as the type of the key can't be relied upon. It's easy enough to do the check using RTTI:
>
> bool isAA(T) () {
> TypeInfo t = typeid(T);
> if (cast(TypeInfo_AssociativeArray) t) {
> return true;
> } else {
> return false;
> }
> }
>
> But of course that is a runtime check, and this should really be a compile-time check. (Also, the various subclasses of TypeInfo are undocumented, so I'm not sure if it's a good idea to rely on them.)
>
> Anyone else have some template judo to share?
>
> -Kirk McDonald
template isAA(T)
{
const isAA = is((cast(T)null).keys);
}
???
or something like that
|
June 21, 2006 Re: static if check for array and AA | ||||
---|---|---|---|---|
| ||||
Posted in reply to BCS | BCS wrote: > Kirk McDonald wrote: > >> I'm fairly certain I've seen this come up before, but I can't seem to rediscover the thread. >> >> I'm trying to write a static if condition to check whether a certain type is an array, and another check for an associative array. The former proved to be moderately simple: >> >> bool isArray(T) () { >> static if (is(typeof(T.init[0])[] == T)) { >> return true; >> } else { >> return false; >> } >> } >> >> Note that this only checks for dynamic arrays. >> >> Associative arrays are harder. The above trick can't quite work as the type of the key can't be relied upon. It's easy enough to do the check using RTTI: >> >> bool isAA(T) () { >> TypeInfo t = typeid(T); >> if (cast(TypeInfo_AssociativeArray) t) { >> return true; >> } else { >> return false; >> } >> } >> >> But of course that is a runtime check, and this should really be a compile-time check. (Also, the various subclasses of TypeInfo are undocumented, so I'm not sure if it's a good idea to rely on them.) >> >> Anyone else have some template judo to share? >> >> -Kirk McDonald > > > > template isAA(T) > { > const isAA = is((cast(T)null).keys); > } > > ??? > > or something like that Now there's an idea... The templates are now: template isArray(T) { const bool isArray = is(typeof(T.init[0])[] == T); } template isAA(T) { const bool isAA = is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == T); } I'd forgotten about those .keys and .values properties. :-) -Kirk McDonald |
June 21, 2006 Re: static if check for array and AA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kirk McDonald | How bout this ? // ---- import std.stdio; void main() { alias char[][int[]] Foo; static if (is(typeof(Foo.keys))) { static if (is(typeof(Foo.values))) { static if (is(Foo : typeof(Foo.values[0])[typeof(Foo.keys[0])])) { writefln("AA !"); } else writefln("!AA3"); } else writefln("!AA2"); } else writefln("!AA1"); } // ---- -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/ |
June 21, 2006 Re: static if check for array and AA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kirk McDonald | Kirk McDonald wrote:
>
> I'd forgotten about those .keys and .values properties. :-)
For extra credit, come up with a simple way to detect static arrays that doesn't rely on implementation-defined behavior. :-)
Sean
|
June 22, 2006 Re: static if check for array and AA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote: > Kirk McDonald wrote: > >> >> I'd forgotten about those .keys and .values properties. :-) > > > For extra credit, come up with a simple way to detect static arrays that doesn't rely on implementation-defined behavior. :-) > > > Sean My first stab at this is this non-working template: template isStaticArray(T) { const bool isStaticArray = is(typeof(T.init[0])[T.length] == T); } My reasoning being a bit of the spec that claims "length" is a compile-time constant for static arrays. Makes sense, might even be true... but it turns out something else entirely is wrong: [inittest.d] import std.stdio; void main() { int[] a; int[10] b; writefln("%s\n%s", typeof(a).init, typeof(b).init ); static if(is(typeof(typeof(b).init) == int)) { writefln("(int[10]).init is an int!"); } } $ dmd inittest $ ./inittest [] 0 (int[10]).init is an int! Wait, what? It turns out the above template fails because "is(typeof(T.init[0]))" fails, as it doesn't describe a valid type. (You can't subscript an int!) This oddity actually makes our job easier, as we see below. It also seems that T.length isn't a compile time constant after all (or at least the template doesn't work if I use it), but there's an easy workaround: Divide T's sizeof by T.init's sizeof. The working template, then, is: template isStaticArray(T) { const bool isStaticArray = is(typeof(T.init)[(T).sizeof / typeof(T.init).sizeof] == T); } Ugly! But it works. The complete test suite I have is: [arraytest.d] import std.stdio; template isArray(T) { const bool isArray = is(typeof(T.init[0])[] == T); } template isStaticArray(T) { const bool isStaticArray = is(typeof(T.init)[(T).sizeof / typeof(T.init).sizeof] == T); } template isAA(T) { const bool isAA = is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == T); } void main() { int i; int[] j; int[10] l; int[int] k; Object o = new Object; writefln("%s", isArray!(typeof(i))); writefln("%s", isArray!(typeof(j))); writefln("%s", isArray!(typeof(l))); writefln("%s", isArray!(typeof(k))); writefln("%s", isArray!(typeof(o))); writefln(""); writefln("%s", isStaticArray!(typeof(i))); writefln("%s", isStaticArray!(typeof(j))); writefln("%s", isStaticArray!(typeof(l))); writefln("%s", isStaticArray!(typeof(k))); writefln("%s", isStaticArray!(typeof(o))); writefln(""); writefln("%s", isAA!(typeof(i))); writefln("%s", isAA!(typeof(j))); writefln("%s", isAA!(typeof(l))); writefln("%s", isAA!(typeof(k))); writefln("%s", isAA!(typeof(o))); } -Kirk McDonald |
June 22, 2006 Re: static if check for array and AA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote:
> Kirk McDonald wrote:
>
>>
>> I'd forgotten about those .keys and .values properties. :-)
>
>
> For extra credit, come up with a simple way to detect static arrays that doesn't rely on implementation-defined behavior. :-)
>
>
> Sean
Just a WAG, but would policys (Alexandrescu) do this?
|
June 22, 2006 Re: static if check for array and AA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kirk McDonald | Kirk McDonald wrote:
> Sean Kelly wrote:
>> Kirk McDonald wrote:
>>
>>>
>>> I'd forgotten about those .keys and .values properties. :-)
>>
>>
>> For extra credit, come up with a simple way to detect static arrays that doesn't rely on implementation-defined behavior. :-)
>>
>>
>> Sean
>
> My first stab at this is this non-working template:
>
> template isStaticArray(T) {
> const bool isStaticArray = is(typeof(T.init[0])[T.length] == T);
> }
>
> My reasoning being a bit of the spec that claims "length" is a compile-time constant for static arrays. Makes sense, might even be true... but it turns out something else entirely is wrong:
>
> [inittest.d]
> import std.stdio;
>
> void main() {
> int[] a;
> int[10] b;
> writefln("%s\n%s",
> typeof(a).init,
> typeof(b).init
> );
> static if(is(typeof(typeof(b).init) == int)) {
> writefln("(int[10]).init is an int!");
> }
> }
>
> $ dmd inittest
> $ ./inittest
> []
> 0
> (int[10]).init is an int!
>
> Wait, what?
>
> It turns out the above template fails because "is(typeof(T.init[0]))" fails, as it doesn't describe a valid type. (You can't subscript an int!)
>
> This oddity actually makes our job easier, as we see below.
>
> It also seems that T.length isn't a compile time constant after all (or at least the template doesn't work if I use it), but there's an easy workaround: Divide T's sizeof by T.init's sizeof. The working template, then, is:
>
> template isStaticArray(T) {
> const bool isStaticArray =
> is(typeof(T.init)[(T).sizeof / typeof(T.init).sizeof] == T);
> }
>
> Ugly! But it works.
Thanks :-) I was trying to sort something like this out the other day and couldn't come up with a working syntax... but then I'd completely forgotten about tricks with .init. At the time, I was thinking it might be nice if this detected static arrays:
template isStaticArray( T : T[int] ) {
const bool isStaticArray = true;
}
template isStaticArray( T ) {
const bool isStaticArray = false;
}
But since the type identifier would still be different from dynamic arrays, specializing templates for all arrays (dynamic and static) is still annoying:
template fn( T, bool isArray : true = isStaticOrDynamicArray!(T) ) {
void fn( T ar ) {}
}
Then more mess to determine the element type of the array, etc.
I'm starting to wonder if C++ style template specialization is even the correct way to go about things in D, as it seems far more flexible to use a single generic wrapper containing a big static if block. This seems to be the rough equivalent to concepts in D, with the drawback that at that point the template will either be instantiated or it won't and compilation will halt.
Sean
|
June 22, 2006 Re: static if check for array and AA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kirk McDonald | In article <e7djp7$42g$1@digitaldaemon.com>, Kirk McDonald says... >It turns out the above template fails because "is(typeof(T.init[0]))" fails, as it doesn't describe a valid type. (You can't subscript an int!) Yes. I've been reporting this a couple of time, but never gotten any (official) response on whether this is the intended behavior. Static arrays are the only type for which typeof(T.init) != T. So the simplest test for a static array is: template isStaticArray(T) { const bool isStaticArray = !is(typeof(T.init) == T); } But having this special case for static arrays complicates template code in many cases. /Oskar |
June 22, 2006 Re: static if check for array and AA | ||||
---|---|---|---|---|
| ||||
Posted in reply to Oskar Linde | Oskar Linde wrote:
> In article <e7djp7$42g$1@digitaldaemon.com>, Kirk McDonald says...
>
>> It turns out the above template fails because "is(typeof(T.init[0]))" fails, as it doesn't describe a valid type. (You can't subscript an int!)
>
> Yes. I've been reporting this a couple of time, but never gotten any (official)
> response on whether this is the intended behavior. Static arrays are the only type for which typeof(T.init)
> != T.
This is also somewhat close to implementation-specific behavior. I'd prefer to have a more formal means of detecting static arrays.
Sean
|
Copyright © 1999-2021 by the D Language Foundation