Implicit conversions for AA keys

Timon Gehr timon.gehr at gmx.ch
Sat Mar 24 04:34:56 PDT 2012


On 03/24/2012 01:20 AM, H. S. Teoh wrote:
> On Fri, Mar 23, 2012 at 10:53:10PM +0100, Timon Gehr wrote:
>> On 03/23/2012 10:07 PM, Timon Gehr wrote:
>>>
>>> I see. An alternative solution (one that does not make AAs depend on
>>> Phobos and is more slick) would be to use the const qualified key type
>>> for lookup (that is what const is for) and to have immutable keys for
>>> stores. For types that define .idup, there would be another overload of
>>> opIndexAssign that can take a const qualified key.
>>
>> Proof of concept:
> [...]
>
> Hmm. I decided that perhaps the full-fledged std.conv.to is a bit of an
> overkill, so I revised the AA code to compromise between needing
> std.conv.to and still deliver what Andrei wants.
>
> Basically, I have a template that defines AA key compatibility, where
> compatibility means that given an AA with key type Key and a key k of
> type K, k is considered compatible if:
>
> - k==K.init is valid (i.e. they can be compared);
> - (At least) one of the following holds:
>     - is(immutable(K) == immutable(Key))
>     - is(typeof(k.idup) == Key)
>     - Key is a static array of length N, and k[0..N] is valid.
>     - is(K : Key)
>
> For the first case (is(immutable(K)==immutable(Key)), which means K and
> Key have the "same representation") and the second case (K.idup yields
> Key), we can basically assume that K.toHash() is consistent with
> Key.toHash(). When creating a new entry, we just assign K to Key, or
> K.idup to Key as necessary.
>
> For the third case, we can just slice the input array when comparing or
> assigning to a new entry (this will throw an Error if the input array
> has the wrong length). I decided to be permissive and compute the hash
> on the entire array, if the length doesn't match it will fail anyway, so
> it's OK to lookup an array of mismatching length in an AA with static
> array keys, as long as you don't try to store the key into it.
>
> Lastly, if is(K : Key) holds but none of the others do, then convert the
> key before computing the hash:
>
> 	Key key = k;	// implicit conversion
> 	return key.toHash();
>
> This ensures the int->double conversion works correctly. Creating a new
> entry can just use straight assignment, due to the implicit conversion.
>
> I've added these changes on github in a branch:
>
> 	https://github.com/quickfur/New-AA-implementation/tree/keyconv
>
> Andrei, please try it out and see if it works on the cases you have in
> mind. :-)
>
>
> T
>

This solution creates unnecessary template bloat for every implicit 
conversion, duplicates compiler logic, and I think it does not work 
correctly because of other issues. I have refined my proof of concept.

Consider this:

template getConstQual(T){
	static if(is(T _ == immutable(U),U)) alias const(getConstQual!U) r;
	else static if(is(T _ == const(U),U)) alias const(getConstQual!U) r;
	else static if(is(T _ == inout(U),U)) alias const(getConstQual!U) r;
	else static if(is(T _ == shared(U),U)) alias const(getConstQual!U) r;
	else static if(is(T _ == U[],U)) alias const(getConstQual!U[]) r;
	else static if(is(T _ == U*,U)) alias const(getConstQual!U*) r;
	else alias const(T) r;
	alias r getConstQual;
}

struct AA(Key, Value) if(is(Key==immutable(Key))){
	Value[Key] payload;
	auto opIndex(getConstQual!Key k){return payload[cast(immutable)k];}
	auto opIndexAssign(Value v, Key k){return payload[cast(immutable)k]=v;}
	static if(is(typeof(getConstQual!Key.init.idup):Key)){
		auto opIndexAssign(Value v, getConstQual!Key k){
			if(auto p = (cast(immutable)k) in payload) return *p=v;
			return this[k.idup]=v;
		}
	}
}
template AA(Key, Value) 
if(!is(Key==immutable(Key))&&is(Key:immutable(Key))){
	alias AA!(immutable(Key), Value) AA;
}


void main() {
	AA!(immutable(double)[], int) aa;
	aa[[1.0,2.0,3.0]]=2; // works, with no .idup!
	aa[[1,2,3]]=2;       // ditto
	AA!(dstring,int) ab;
	ab["123"]=2;         // just works
	char[3] c= "123";
	AA!(short,int) ac;
	ac[2]=2;             // so does this
}

This nicely resolves all the implementation problems you have 
encountered/will encounter, because it does not rely on IFTI. I think 
you should follow this strategy.








More information about the Digitalmars-d mailing list