www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 8823] New: static if (A || B) != static if (A) else if (B) in some cases

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=8823

           Summary: static if (A || B) != static if (A) else if (B) in
                    some cases
           Product: D
           Version: D2
          Platform: All
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: beatgammit gmail.com



Test platform:

Fedora 17 Linux 3.5.4-2.fc17.x86_64
DMD64 D Compiler v2.060
rdmd build 20120724


The following works:

import std.stdio;

class A {
    string s;
}

void main() {
    A a = new A;
    foreach (t; __traits(allMembers, A)) {
        static if (
                is(typeof(__traits(getMember, A, t)) == function) || 
                is(typeof(__traits(getMember, a, t)) == function) ||
                t == "Monitor"
        ) {
            continue;
        }

        __traits(getMember, a, t) = "hello";
    }
}

But if I split up the static if, it won't compile:

import std.stdio;

class A {
    string s;
}

void main() {
    A a = new A;
    foreach (t; __traits(allMembers, A)) {
        static if (is(typeof(__traits(getMember, A, t)) == function)) {
            continue;
        } else if (is(typeof(__traits(getMember, a, t)) == function)) {
            continue;
        } else if (t == "Monitor") {
            continue;
        }

        writeln(t);
        __traits(getMember, a, t) = "hello"; // error
    }
}

I get the following errors:

test.d(19): Error: not a property a.toString
test.d(19): Error: not a property a.toHash
test.d(19): Error: not a property a.opCmp
test.d(19): Error: not a property a.opEquals
test.d(19): Error: __traits(getMember,a,"Monitor") is not an lvalue

If I comment out the offending line, I only get "s" as output, as expected.

Also, if I use an else branch instead, I still get a compile error:

import std.stdio;

class A {
    string s;
}

void main() {
    A a = new A;
    foreach (t; __traits(allMembers, A)) {
        static if (is(typeof(__traits(getMember, A, t)) == function)) {
            continue;
        } else if (is(typeof(__traits(getMember, a, t)) == function)) {
            continue;
        } else if (t == "Monitor") {
            continue;
        } else {
            writeln(t);
            __traits(getMember, a, t) = "hello"; // error
        }
    }
}

test.d(18): Error: __traits(getMember,a,"Monitor") is not an lvalue

This is even more curious, because I explicitly accounted for this case (and it
works in the combined static if). As in the above example, commenting out the
offending line works as expected.


What did I expect:

The if/else branches would behave the same at compile time as it's runtime
equivalent. __traits(getMember, a, t) should not be evaluated if any of the
above if/else branches are true, since it would be an unreachable statement
given the continue.

I was very surprised that combining them into one if conditional worked as
expected, but if one works, they all should work.


Notes:

I'm building a marshaller, so only data types should be considered. Since there
is no isVariable for __traits, this must be done in a loop. Many of the members
cannot be marshalled, so this makes for a messy if conditional, so splitting it
up (into checks on static/instance members) can be more readable.

This particular case can be easily avoided, but a more complicated case (one
branch continues and another breaks) would not be so easy to rectify.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 14 2012
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=8823




It also does not work reliably if I change them to regular if blocks:

    import std.stdio;

    class A {
        string s;
    }

    void main() {
        A a = new A;
        foreach (t; __traits(allMembers, A)) {
            static if (is(typeof(__traits(getMember, A, t)) == function)) {
                continue;
            }
            static if (is(typeof(__traits(getMember, a, t)) == function)) {
                continue;
            }
            static if (t == "Monitor") {
                continue;
            }

            __traits(getMember, a, t) = "hello";
        }
    }


Tt works if I nest under a common else:

    import std.stdio;

    class A {
        string s;
    }

    void main() {
        A a = new A;
        foreach (t; __traits(allMembers, A)) {
            static if (is(typeof(__traits(getMember, A, t)) == function)) {
                continue;
            } else {
                static if (is(typeof(__traits(getMember, a, t)) == function)) {
                    continue;
                } else {
                    static if (t == "Monitor") {
                        continue;
                    } else {
                        __traits(getMember, a, t) = "hello";
                    }
                }
            }
        }
    }

It seems the workaround is nesting.

It looks as if 'else if' in general doesn't work as expected. It serves as a
regular 'if', but without the knowledge from the preceding 'if' conditionals.
In my implementation, I have more than 5 conditionals (all different bodies),
but each assumes that the previous conditionals evaluated to false.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 15 2012
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=8823


Dmitry Olshansky <dmitry.olsh gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |dmitry.olsh gmail.com
         Resolution|                            |INVALID



09:28:15 PDT ---
Basically:

static if(...)
else static if(...){
}

Note the second 'static' before if.
Fairly common gotcha.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 15 2012