Dmitry Bubnenkov
Dmitry Bubnenkov

Reputation: 9859

How to check Variant for null?

I am getting answer from DB and need to check if it is not null before placing it's to value.

I tried few variants of checking, but my code is still crush:

foreach(i, point;myPointsLonLat)
{                   

    try
    {
        carGPSPoint cargpspoint;
        cargpspoint.id = point[0].coerce!ulong;

        cargpspoint.recordDate = DateTime.fromSimpleString(point[1].coerce!string).toISOExtString(); // some magic to get string in 2016-10-31T15:37:24 format
        if(point[2].hasValue) //check if we have some data
            cargpspoint.velocity = point[2].coerce!double;
        if(point[3].hasValue)
            cargpspoint.lat = point[3].coerce!double;
        if(point[4].hasValue)                   
            cargpspoint.lon = point[4].coerce!double;
        cargpspoints[i] = cargpspoint;
        b.next();
    }
    catch(Exception e)
    {
        writeln("\n----------------------------ERRRRRR-----------------------");
        writeln(point);
        writeln("1111: ", point[2].coerce!double);
        writeln("2222: ", point[3].coerce!double);
        writeln("3333: ", point[4].coerce!double);
        writeln(e.msg);
    }
}

Output:

----------------------------ERRRRRR-----------------------
Row([1478698195002489886, 2016-Nov-09 13:29:55, 153, null, null], [false, false, false, true, true])
1111: 153

object.Exception@C:\D\dmd2\windows\bin\..\..\src\phobos\std\variant.d(823): Type typeof(null) does not convert to double

As you see it's print 1111: 153. But crashing on other null variables.

I also tried:

    if(point[2].type !is null) //check if we have some data
        cargpspoint.velocity = point[2].coerce!double;
    if(point[3].type !is null)
        cargpspoint.lat = point[3].coerce!double;
    if(point[4].type !is null)                  
        cargpspoint.lon = point[4].coerce!double;

Same result. What I am doing wrong?

Upvotes: 3

Views: 1693

Answers (2)

jpf
jpf

Reputation: 517

Here's a solution to implement the isNull function and a hasValue2 function in the way you wanted:

import std.variant;
import std.stdio;

void main()
{
    Variant v;
    writefln("%s %s %s", v.hasValue, !v.isNull, v.hasValue2);
    v = null;
    writefln("%s %s %s", v.hasValue, !v.isNull, v.hasValue2);
    v = "";
    writefln("%s %s %s", v.hasValue, !v.isNull, v.hasValue2);
}

@property bool isNull(Variant v)
{
    return v.type == typeid(typeof(null));
}

@property bool hasValue2(Variant v)
{
    return v.hasValue && !v.isNull;
}

Result:

false true false
true false false
true true true

So in your code you should check for typeid(typeof(null)) instead. You might be right that hasValue should check for typeof(null) as well. IIRC Variant predates typeof(null), nowadays it might even make sense to use only typeof(null) and never allow uninitialized Variants.

Please start a discussion at https://forum.dlang.org/group/general or file a bug report at https://issues.dlang.org to discuss this with the appropriate library maintainers.

Upvotes: 2

Adam D. Ruppe
Adam D. Ruppe

Reputation: 25595

hasValue checks if it has been initialized, and the database library does initialize it, just to null.

I'd suggest checking the type directly:

 if(auto pt = point[3].peek!double)
                cargpspoint.lat = *pt;

peek checks if it has that exact type and returns a pointer to the value if it does. It is an exact match, meaning if it is float or something else, this won't work, so make sure you are matching what the database gives you (that's best for performance and accuracy anyway), but then it will be null and thus skip the if it isn't right and you can set if it is.

Just repeat that pattern for all your points.

Upvotes: 2

Related Questions