Skip to content

Design flaw: Swapping struct fields yields unexpected value #12064

Description

@bcrist

Zig Version

0.10.0-dev.2880+6f0807f50

Steps to Reproduce

const std = @import("std");

const X = struct {
    a: u16,
    b: u16,
};


test {
    var x = X {
        .a = 47,
        .b = 234,
    };

    // swap x.a and x.b
    x = .{
        .a = x.b,
        .b = x.a,
    };

    try std.testing.expectEqual(@as(u16, 234), x.a);
    try std.testing.expectEqual(@as(u16, 47), x.b);
}

Expected Behavior

Conceptually, I expect everything on the right side of an assignment to be evaluated before the left side is modified.

So x.a should be 234 and x.b should be 47, and the test should pass.

Actual Behavior

Both x.a and x.b ends up being equal to 234, and the test fails:

Test [1/1] test ""... expected 47, found 234
Test [1/1] test ""... FAIL (TestExpectedEqual)
C:\...\zig\lib\std\testing.zig:79:17: 0x7ff607721fc8 in td.testing.expectEqual (test.obj)
                return error.TestExpectedEqual;
                ^
C:\...\swap.zig:21:5: 0x7ff60772176a in est "" (test.obj)
    try std.testing.expectEqual(@as(u16, 47), x.b);
    ^
0 passed; 0 skipped; 1 failed.

It would appear that the compiler has transformed the swap into the equivalent of:

x.a = x.b;
x.b = x.a;

The documentation doesn't say much about order of evaluation guarantees as far as I can tell, so maybe this is just undefined behavior in zig, but if that's the case, it seems like a pretty big footgun.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    breakingImplementing this issue could cause existing code to no longer compile or have different behavior.use caseDescribes a real use case that is difficult or impossible, but does not propose a solution.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions