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

Proposal: C99-style designated initialisers #3435

Open
oskarnp opened this issue Oct 11, 2019 · 5 comments
Open

Proposal: C99-style designated initialisers #3435

oskarnp opened this issue Oct 11, 2019 · 5 comments
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@oskarnp
Copy link

oskarnp commented Oct 11, 2019

Proposal: Add designated initialisers from enum values, similar to C99.

Example:

const FooEnum = enum { A, B, C };

const Foo = struct {
  name: []const u8,
};

const FooTable = [_]Foo{
  [FooEnum.B] = Foo{.name = "b"},  // placed at memory location [1]
  [FooEnum.A] = Foo{.name = "a"},  // placed at memory location [0]
  [FooEnum.C] = Foo{.name = "c"},  // placed at memory location [2]
};

// Lookup of fooTable[FooEnum.A].name is "a"
// Lookup of fooTable[FooEnum.B].name is "b"
// Lookup of fooTable[FooEnum.C].name is "c"

@andrewrk
Copy link
Member

Note that you can accomplish this with status quo zig using comptime features.

@oskarnp
Copy link
Author

oskarnp commented Oct 11, 2019

@andrewrk Could you give an example? I'm not sure what you are referring to.

@nrdmn
Copy link
Contributor

nrdmn commented Oct 12, 2019

It's not pretty but it works. I'm not sure if we can simplify init() here. Maybe we can access the declared return type of the function from within itself, or we'll have to wait for #447.

const std = @import("std");

const FooEnum = enum {
    A,
    B,
    C,
};

const Foo = struct {
    name: []const u8,
};

fn init(comptime T: type, a: []const T) b: {
    var max = 0;
    for (a) |x| {
        if (x.key < 0) {
            @compileError("negative index");
        }
        if (x.key > max) {
            max = x.key;
        }
    }
    break :b [max+1]std.meta.fieldInfo(T, "value").field_type;
} {
    var max = 0;
    for (a) |x| {
        if (x.key < 0) {
            @compileError("negative index");
        }
        if (x.key > max) {
            max = x.key;
        }
    }
    var r: [max+1]std.meta.fieldInfo(T, "value").field_type = undefined;
    for (a) |x| {
        r[x.key] = x.value;
    }
    return r;
}

pub fn main() !void {
    const T = struct {
        key: comptime_int,
        value: Foo,
    };
    const a = comptime init(T, ([_]T{
        T {
            .key = @enumToInt(FooEnum.B),
            .value = Foo{.name = "b",},
        },
        T {
            .key = @enumToInt(FooEnum.A),
            .value = Foo{.name = "a",},
        },
        T {
            .key = @enumToInt(FooEnum.C),
            .value = Foo{.name = "c",},
        },
    })[0..]);

    var buf: [100]u8 = undefined;
    for (a) |x| {
        try (try std.io.getStdOut()).write(try std.fmt.bufPrint(buf[0..], "{}\n", x));
    }
}

@oskarnp
Copy link
Author

oskarnp commented Oct 12, 2019

Yikes. Thanks, @nrdmn. So I think my proposal would be a pretty good feature then.

@daurnimator daurnimator added the proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. label Oct 12, 2019
@andrewrk andrewrk added this to the 0.7.0 milestone Oct 14, 2019
@cshenton
Copy link
Contributor

cshenton commented Apr 5, 2020

Another aspect of supporting C99 style designated initialisers is how translate-c sets default fields. Consider the following call to a sokol_gfx.h api in C99 (where sg_buffer_desc has many other fields with meaningful default 0 values).

sg_buffer ibuf = sg_make_buffer(&(sg_buffer_desc){    
    .type = SG_BUFFERTYPE_INDEXBUFFER,
    .size = sizeof(indices),
    .content = indices,
});

If translate-c generated zig structs with 0 defaults, then in zig we could have an almost identical syntax:

const ibuf = sg_make_buffer(&sg_buffer_desc{
    .type = .SG_BUFFERTYPE_INDEXBUFFER,
    .size = @sizeOf(@typeOf(indices)),
    .content = &indices[0],
});

As it stands though this isn't the case and the resulting zig code looks more like C89.

var desc = std.mem.zeros(sg_buffer_desc);
desc.type = .SG_BUFFERTYPE_INDEXBUFFER;
desc.size = @sizeOf(@typeOf(indices));
desc.content = &indices[0];
const ibuf = sg_make_buffer(desc);

Which is a shame since the first zig example is truer to both the intended C API and what a similar zig API might look like. There are of course, potentially downsides to defaulting translated structs' fields to 0, and those should be considered.

@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Oct 27, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 May 19, 2021
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 Nov 23, 2021
@andrewrk andrewrk modified the milestones: 0.10.0, 0.11.0 Apr 16, 2022
@andrewrk andrewrk modified the milestones: 0.11.0, 0.12.0 Apr 9, 2023
@andrewrk andrewrk modified the milestones: 0.13.0, 0.12.0 Jul 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

No branches or pull requests

5 participants