www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 3718] New: InExpression does not support two-or-more-dimensional associative array.

http://d.puremagic.com/issues/show_bug.cgi?id=3718

           Summary: InExpression does not support two-or-more-dimensional
                    associative array.
           Product: D
           Version: unspecified
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: michal.minich gmail.com



PST ---
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.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 18 2010