Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

raw unions #144

Closed
andrewrk opened this issue Apr 23, 2016 · 8 comments
Closed

raw unions #144

andrewrk opened this issue Apr 23, 2016 · 8 comments
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase.
Milestone

Comments

@andrewrk
Copy link
Member

andrewrk commented Apr 23, 2016

Zig already supports tagged unions (#5) but for better C compatibility Zig needs to support C-style unions as well. Also, tagged unions have the tag field, and if programmers don't want that field, they're out of luck. Supporting raw unions is additional power that is needed to compete with C.

However, we want to encourage programmers to try to use tagged unions (enum) instead. It's not really possible for debug instrumentation to protect against the dangers of unions.

@andrewrk andrewrk added the enhancement Solving this issue will likely involve adding new logic or components to the codebase. label Apr 23, 2016
@andrewrk andrewrk added this to the 0.1.0 milestone Apr 23, 2016
@andrewrk andrewrk modified the milestones: 0.1.0, 0.2.0 Apr 20, 2017
@kyle-github
Copy link

If the purpose is for C interop, then there are other factors. Take the following example:

union { int a; void *b; } foo;

If you are on a 64-bit system with 32-bit ints and 64-bit pointers, then the value you get for 'a' will depend on the alignment requirements and byte order of the CPU and compiler. To make such a union interoperable between Zig and C, you would need to have Zig match the byte ordering and alignment used by the C compiler. In practice the byte order is probably not as big of a problem, but the alignment might be different.

@andrewrk
Copy link
Member Author

extern union is guaranteed to be C ABI compatible.

It's an open question what a non-extern union will look like.

@kyle-github
Copy link

Are there many use cases for a non-extern union that is not enum?

@andrewrk
Copy link
Member Author

andrewrk commented Nov 15, 2017

Here's the current plan for unions:

const Foo = union {
    name1: u32,
    name2: f64,
};
const foo = Foo { .name2 = 12.34 };

Unions do not side-step Type Based Alias Analysis

@andrewrk
Copy link
Member Author

I ran into an LLVM bug with debug info in 5.0.0 when implementing this.

I'm looking for a workaround.

@andrewrk
Copy link
Member Author

Non-extern unions will have the following safety feature:

  • Every distinct type instance in zig gets a unique type instance id, which is an integer with the smallest number of bits needed to represent it
  • Non-extern unions which have > 1 unique type in the union, have a secret type_instance_id field, which is initialized to the type instance id of void
  • Writing through a union field sets the type_instance_id to the appropriate type
  • Reading through a union field asserts that the type_instance_id is correct
  • This safety feature is disabled in ReleaseFast mode, and can be disabled per union with comptime { @setDebugSafety(Foo, false); }

andrewrk added a commit that referenced this issue Nov 15, 2017
@andrewrk
Copy link
Member Author

andrewrk commented Nov 16, 2017

if you do this:

const Foo = union {
    name1: u32,
    name2: f64,
};

test "aoeu" {
    var foo = Foo { .name2 = 12.34 };
    bar(&foo.name1);
}

fn bar(x: &u32) {
    *x = 1234;
}

How is zig supposed to know how to write the secret field indicating
that the active union member is name1?

I'll tell you how.

Accessing union fields by name will only give a const pointer to
the field value, and will emit a debug safety check looking at
the secret field.

If you want a mutable pointer to a union field, you do this:

test "aoeu" {
    var foo = Foo { .name2 = 12.34 };
    bar(@mutableUnionPtr(foo, "name1"));
}

@mutableUnionPtr does these things:

  • if debug safety is enabled, modifies the secret field telling which type the union is
    • if the secret field type is changed, sets the union's value to undefined
  • returns a pointer to a union field

andrewrk added a commit that referenced this issue Nov 16, 2017
@andrewrk
Copy link
Member Author

More adjustments:

Nevermind about @mutableUnionPtr. We can use normal address operators.

  • Change the secret field to be which union field is active instead of which distinct type is active.
  • To change which field of a union is active, reassign the whole union.
  • Field access of a union field activates the safety check of which field is active.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Solving this issue will likely involve adding new logic or components to the codebase.
Projects
None yet
Development

No branches or pull requests

2 participants