digitalmars.D - static if check for array and AA
- Kirk McDonald (29/29) Jun 21 2006 I'm fairly certain I've seen this come up before, but I can't seem to
- BCS (7/44) Jun 21 2006 template isAA(T)
- Kirk McDonald (11/61) Jun 21 2006 Now there's an idea... The templates are now:
- Tom S (16/16) Jun 21 2006 How bout this ?
- Sean Kelly (4/6) Jun 21 2006 For extra credit, come up with a simple way to detect static arrays that...
- Kirk McDonald (77/88) Jun 22 2006 My first stab at this is this non-working template:
- Sean Kelly (25/87) Jun 22 2006 Thanks :-) I was trying to sort something like this out the other day
- Oskar Linde (11/13) Jun 22 2006 Yes. I've been reporting this a couple of time, but never gotten any (of...
- Sean Kelly (4/13) Jun 22 2006 This is also somewhat close to implementation-specific behavior. I'd
- Bruno Medeiros (13/31) Jun 23 2006 I'm not sure that is implementation-specific behavior. I suspect that
- David Medlock (2/13) Jun 22 2006 Just a WAG, but would policys (Alexandrescu) do this?
- Don Clugston (16/64) Jun 23 2006 template isAA(T)
- BCS (3/5) Jun 23 2006 Maybe, but it should it be standardized as part of D? (I hesitate to say...
- Don Clugston (5/11) Jun 25 2006 It should definitely be standardised. Failure to standardise the name
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
Jun 21 2006
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 McDonaldtemplate isAA(T) { const isAA = is((cast(T)null).keys); } ??? or something like that
Jun 21 2006
BCS wrote:Kirk McDonald wrote: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 McDonaldI'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 McDonaldtemplate isAA(T) { const isAA = is((cast(T)null).keys); } ??? or something like that
Jun 21 2006
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 +/
Jun 21 2006
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
Jun 21 2006
Sean Kelly wrote:Kirk McDonald wrote: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 McDonaldI'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
Jun 22 2006
Kirk McDonald wrote:Sean Kelly wrote: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. SeanKirk McDonald wrote: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.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
Jun 22 2006
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
Jun 22 2006
Oskar Linde wrote:In article <e7djp7$42g$1 digitaldaemon.com>, Kirk McDonald says...This is also somewhat close to implementation-specific behavior. I'd prefer to have a more formal means of detecting static arrays. SeanIt 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.
Jun 22 2006
Sean Kelly wrote:Oskar Linde wrote:I'm not sure that is implementation-specific behavior. I suspect that that is related to the fact that static arrays are the only type that cannot be assigned to a value of the same type (sar1 = sar2). So in order for something like this: T sar = T.init ; to work for all types, then T.init had to an element of the static array. I think that all of this (arrays not being proper value types) is pretty inconsistent, although most of us are so used to C and C++ that we don't even notice or are bothered by it -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DIn article <e7djp7$42g$1 digitaldaemon.com>, Kirk McDonald says...This is also somewhat close to implementation-specific behavior. I'd prefer to have a more formal means of detecting static arrays. SeanIt 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.
Jun 23 2006
Sean Kelly wrote:Kirk McDonald wrote:Just a WAG, but would policys (Alexandrescu) do this?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
Jun 22 2006
BCS wrote:Kirk McDonald wrote:template isAA(T) { const bool isAA = T.mangleof[0]=='H'; } template isStaticArray(T) { const bool isStaticArray = T.mangleof[0]=='G'; } template isDynamicArray(T) { const bool isDynamicArray = T.mangleof[0]=='A'; } You can check for ANYTHING in this way. Of course this relies on the name mangling algorithm which is not yet stabilised and documented -- but which should be, by DMD 1.0.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 McDonaldtemplate isAA(T) { const isAA = is((cast(T)null).keys); } ??? or something like that
Jun 23 2006
Don Clugston wrote:Of course this relies on the name mangling algorithm which is not yet stabilised and documented -- but which should be, by DMD 1.0.Maybe, but it should it be standardized as part of D? (I hesitate to say yes.)
Jun 23 2006
BCS wrote:Don Clugston wrote:It should definitely be standardised. Failure to standardise the name mangling and the ABI was one of the major mistakes of C++. It makes linking between different vendors virtually impossible (and it's why so many more libraries use C linking than C++).Of course this relies on the name mangling algorithm which is not yet stabilised and documented -- but which should be, by DMD 1.0.Maybe, but it should it be standardized as part of D? (I hesitate to say yes.)
Jun 25 2006