Variant[Variant]
Ali Çehreli
acehreli at yahoo.com
Tue Aug 27 11:32:46 PDT 2013
On 08/27/2013 03:53 AM, Jason den Dulk wrote:
> I uploaded a new version with a main routine. So you know, I am using
> DMD 2.063.2 on Fedora 15.
>
> The code should compile with "dmd serialize.d".
And it's here:
http://jaypha.com.au/serialize.d
> I since realized that I was not dealing with a Variant[Variant] but a
> Variant(Variant[Variant]). It didn't seem to like having "[Variant]"
> called upon it.
>
> After extracting it to a V[V] (called tcd1_vn), I noticed something else.
>
> Doing a foreach on it,
>
> foreach (_a_, _b_;tcd1_vn)
> {
> writeln(_a_.type(),",",_b_.type());
> writeln(_a_.get!(string),",",_b_.get!(long));
> }
>
> gives this:
>
> immutable(char)[],long
> a,1
> immutable(char)[],long
> b,2
> immutable(char)[],long
> c,3
>
> So it appears that Variant("a") is a key, but
>
> assert(Variant("a") in tcd1_vn);
>
> fails. Any ideas?
It is definitely a bug. I spent a lot of time on this and figured it out
just before giving up. :) (Actually I figured it out *after* giving up. :p)
The signature of VariantN.toHash() does not match D's expectation so it
is not considered at all. As a result, the default toHash for structs
gets called, which happens to hash by the members of the struct. The
problem is, being a variant type, the members of VariantN are a function
pointer and the storage:
struct VariantN(size_t maxDataSize, AllowedTypesX...)
{
// ...
ptrdiff_t function(OpID selector, ubyte[size]* store, void* data) fptr
= &handler!(void);
union
{
ubyte[size] store;
// conservatively mark the region as pointers
static if (size >= (void*).sizeof)
void* p[size / (void*).sizeof];
}
// ...
}
Since 'store' is just a ubyte[] array, the default toHash for structs
cannot hash it as strings.
VariantN.toHash's signature must be changed accordingly and Phobos must
be recompiled:
// WARNING: Unnecessarily slow because type.getHash() is not nothrow.
size_t toHash() const nothrow @safe
{
try {
return type.getHash(&store);
} catch (Exception) {
return 0;
}
}
The original toHash was this:
size_t toHash()
{
return type.getHash(&store);
}
The other issue is, the compiler did not warn me until I added a const
to the signature. Try to compile this:
size_t toHash() const
{
return type.getHash(&store);
}
./phobos/std/variant.d(822): Warning: toHash() must be declared as
extern (D) size_t toHash() const nothrow @safe, not const @trusted ulong()
The same warning should be given to the naked signature 'size_t
toHash()' as well. (I remember bearophile warning about such problems.)
So, VariantN is broken. It cannot be used as an AA key correctly, at
least when it stores a string. To make matters worse, testing with
Variants that are initialized by literal strings works because the
compiler optimizes the same literal strings.
> Thanks again for helping. I have been reading your online book. I have
> found it quite helpful.
You are very kind. :) However, as this issue proves, the book is
outdated in some parts. At least there is a note for me to update the
toHash signatures in the book: :)
https://code.google.com/p/ddili/source/browse/trunk/src/ders/d.en/object.d#681
So, I will get to this issue eventually. :-/
May I ask you or somebody else to create a bug about VariantN.toHash not
being considered at all. Thank you! :)
Ali
More information about the Digitalmars-d-learn
mailing list