AA key conversion woes
kenji hara
k.hara.pg at gmail.com
Tue Apr 17 19:24:32 PDT 2012
2012年4月18日3:41 H. S. Teoh <hsteoh at quickfur.ath.cx>:
> I'm having some major roadblocks with the AA implementation w.r.t. how
> to store/convert AA key types correctly. I've been working on this for a
> while now but still cannot find a satisfactory solution; hopefully y'all
> can help.
>
> First, in order to take advantage of the compiler's auto-conversion
> magic (such as using literal [1,2,3] for ubyte[] keys, etc.) and to
> avoid template bloat, we must take const(Key) as argument for all key
> lookup methods. So Key must at least be stored as const. But since we
> have to do this already, might as well do it right: Keys should be
> stored as immutable.
>
> The nice thing about this is that we can now *guarantee* that AA's won't
> malfunction due to the user changing stored key values via an external
> mutable reference.
>
> The bad thing about this is how to deal with the various key types that
> the user might try to pass in:
>
> 1) For value types like int, there's no problem: immutable(int)
> interconverts freely with int via assignment, so we can store int keys
> however we like, and we can always hand back unqualified ints to the
> user. So if the user declares int[int], .keys will give int[], and if
> the user declares const(int)[int], then .keys will give back
> const(int)[]. No problem.
>
> 2) Where things get hairy is when non-trivial keys are stored. Take
> arrays for example. If the user declares int[int[]], then we need an
> .idup so that we can store the key as immutable(int)[] (or should that
> be immutable(int[])?). But now if the user passes in an int[] key, we
> will need to .idup it in order to store it. This is acceptable, but what
> should .keys return? If I were the user, I'd expect int[][], but since
> we can't implicitly convert immutable(int)[] to int[], we need a .dup
> for each key. Which introduces unnecessary overhead, since for the most
> part the user doesn't need to change the keys anyway. But handing back
> immutable(int)[][] from .keys will break a lot of existing code.
I think AA key should be immutable, but in some case, whole immutable
is not needed.
- With basic type keys (int, long, double, ...), they have no
indirections, so you can add/remove qualifiers as you expects.
int user_specified_key;
immutable int AA_stored_key = user_specified_key; // add qualifier
copy conversion, it is safe.
- With compound types (arrays, and pointers), if they have no
*mutable* indirections, you can add/remove their head qualifiers with
copy conversion.
int[int[]] aa; // same as int[immutable(int[])]
immutable(int)[] key1;
aa[key1] = 10; // key1 is implicitly convertible to immutable(int[])
int[] key2;
aa[key2] = 10; // Error! key2 is not implicitly convertible to
immutable(int[])
aa[key2.idup] = 10; // valid
int[int*] aa; // same as int[immutable(int*)]
immutable(int)* key1;
aa[key1] = 10; // key1 is implicitly convertible to immutable(int*)
int* key2;
aa[key2] = 10; // Error! key2 is not implicitly convertible to
immutable(int*)
Then, you can check the AA key type with assertion like follows:
template AssociativeArray(Key, Value)
if (is(typeof((ref Key key){
immutable(Key) ikey = key; // Key is implicitly convertible to
immutable(Key)?
})))
{
alias immutable(Key) InterfaceKeyType;
InterfaceKeyType[] keys();
// even if InterfaceKeyType == immutable(string),
// keys[n] can implicitly convertible to string.
private:
struct Slot { InterfaceKeyType* key; ... }
}
> 3) With arrays, things are still not too bad because we have .dup and
> .idup. But what about structs or classes? We do not have .idup if the
> key type is specified as non-immutable, so how should the keys be
> stored? (Besides, do we *want* to clone objects used as AA keys in the
> first place?) And what type should .keys return?
You can apply to them same rule as built-in compound types."If the
given Key type has mutable indirection, whole immutable key is
required, otherwise, you can store keys that head mutable but tail
immutable.
struct S1 { immutable(int)[] arr; }
auto s1m = S1([1,2,3]);
immutable s1i = s1m; // s1i.arr is still immutable, so you can
convert s1 to immutable with copy.
int[S1] aa;
aa[s1m] = 10; // valid, s1m is implicitly convertible to immutable(S1)
struct S2 { int[] arr; }
auto s2m = S2([1,2,3]);
immutable s2i = s2m; // this conversion breaks const system, then
compiler rejects this line.
int[S2] aa;
aa[s2m] = 10; // invalid! user should create immutable copy of s2m explicitly
class C { ... }
auto cm = new C(); // class reference is always reference in D.
immutable ci1 = cm; // so this is always invalid.
immutable ci2 = immutable(C)();
int[C] aa;
aa[cm] = 10; // always invalid, cm is not implicitly convertible to immutable(C)
aa[ci2] = 10; // valid
> 4) What should be done if the key type is shared or inout? (I'm tempted
> to say outright prohibit shared, but people may not like their code
> breaking if they're actually using that in existing code.)
If Key type has inout qualifier, AA implementation should replace it to const.
int[inout(int)[]] --> AssociativeArray!(const(int)[], int)
> I'm tempted to propose that the language should be changed so that AA
> keys are *always* immutable implicitly. That is, writing int[int] is
> exactly the same as writing int[immutable(int)], and .keys will always
> return immutable. This is the "correct" approach IMO, and existing code
> should be fixed if this breaks them. This will simplify a lot of the
> mess above (we can still support .idup for when the user wants to lookup
> mutable keys, etc., but there will be no concessions for .keys to hand
> back mutable keys -- .dup them yourself).
Agreed. It is enough restriction for AA key.
With implicitly convertible to immutable rule I explained above, we
can keep convenient usage.
> But I'm expecting some negative reactions to this hardline approach. :-)
>
> But even then, I'm considering if .keys should return a mutable array if
> the key is a value type (e.g., it's harmless for int[int].keys to return
> int[] because the int's are a copy anyway, and this way user code won't
> be unnecessarily straitjacketed to propagate immutable throughout).
>
> I'd like to hear how people think this should work, so that the new AA
> implementation will be more acceptable.
Thanks.
Kenji Hara
More information about the Digitalmars-d
mailing list