Bug 3718 – InExpression does not support two-or-more-dimensional associative array.

Status
RESOLVED
Resolution
WONTFIX
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2010-01-18T03:12:13Z
Last change time
2018-05-16T14:37:03Z
Assigned to
No Owner
Creator
Michal Minich

Comments

Comment #0 by michal.minich — 2010-01-18T03:12:13Z
While finding if key exists in aa is very easy and 'cool' in D (it even returns pointer to value): float[char] aa1; if ('a' in aa1) ... for two dimensional array it is impossible to use this syntax: float[int][char] aa2; if (123 in *('a' in aa2)) ... = problem if "('a' in aa2)" evaluates to null, because then evaluating "123 in null" references null pointer. Similarly using: if (123 in aa2['a']) does not give desired behavior. ---------------- Simple (and bad) solution would be creating function 'doubleIn' as here for every specific case, which every user of D is doomed to do until better solution is provided in language. aa['a'][123] = 4.56; float* isIn = doubleIn(123, 'a'); float* doubleIn (int i, char ch) { float[int]* first = ch in aa; if (first is null) return null; else return i in *first; } --------------- Possible solution for standard library: Here is templated function "isIn" written by Simen kjaeraas, implemented to work with combination of AAs and normal arrays: template elementTypeOfDepth( T : V[ K ], int depth, V, K ) { static if ( depth == 0 ) { alias V elementTypeOfDepth; } else { alias elementTypeOfDepth!( V, depth -1 ) elementTypeOfDepth; } } template elementTypeOfDepth( T : V[ ], int depth, V ) { static if ( depth == 0 ) { alias V elementTypeOfDepth; } else { alias elementTypeOfDepth!( V, depth -1 ) elementTypeOfDepth; } } elementTypeOfDepth!( T, U.length )* isIn( T : V[ ], V, U... )( T arr, size_t key, U index ) { if ( key < arr.length ) { auto p = arr[ key ]; static if ( U.length > 0 ) { if ( p ) { return isIn( p, index ); } else { return null; } } else { return p; } } else { return null; } } elementTypeOfDepth!( T, U.length )* isIn( T : V[ K ], V, K, U... )( T arr, K key, U index ) { auto p = key in arr; static if ( U.length > 0 ) { if ( p ) { return isIn( *p, index ); } else { return null; } } else { return p; } } Usage: int[char][][int] foo; if ( isIn( foo, 3, 87, 'a' ) ) { writeln( "Excelsior!" ); } --------------- Possible solution for D language I did not consulted compiler implementation, but from its behavior, this simple modification should be enough: the problem with statement "123 in *('a' in aa)" is that if "('a' in aa')" returns null, then next check will fail: (123 in null) -> null reference error. if D simply check if the second part of InExpression is null, and if yes, return null, otherwise evaluate as is currently done. Additional thing would be allowing syntax "123 in ('a' in aa)" -- without the "*" pointer dereference. This could be achieved by adding another "overload" for InExpression which works with pointer to AA. Compiler should already know if the argument of InExpression is AA or pointer to AA.
Comment #1 by dmitry.olsh — 2018-05-16T14:37:03Z
This is trivially doable in library as shown below. And it's a wrong kind of magic for builtin AAs that is hard to "extend" to other types. There are plenty of ways to have nice syntax for this operation with UFCS and friends, so I believe it's not going to happend. No more magic for builtins.