-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Proposal: Optional argument names in function calls #982
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
Comments
Minor note, this would make argument names part of a functions public api. How important do you consider argument reordering to be? I would much prefer this without it personally. |
I don't really have a problem with not having argument reordering, I guess I can see an argument for how it could be confusing. |
What I've seen suggested in 21st Century C to do this without actually supporting it in the language is just to use a throwaway struct. At least in C, this allows for unnamed parameters to be passed in order, and designated initializers to be passed out of order. If the Zig compiler generates this struct on the fly, you can avoid adding entirely new semantics to the parser.
|
Adding onto this, We could add a 'swift' like optional parameter name; for reference it looks like this; func foo(a b: i32) i32 {
// We use 'b'
return b;
}
// You HAVE to use names to access it, I believe
foo(a: i32); This is because often if you want to do names you want nice names to form an api like; I'm pretty unsure about how it would work in Zig but felt it might be worth bringing up. |
Adding another idea into the mix here: One of the thing Zig brings to the table is the comptime integer type. This is where, instead of specifying, e.g. Related issue: #556 (rename int literal and float literal types) It's proposed (See #683) to add syntax so that one can use, e.g. The way this would work is that the expression Taking this a step further, we could introduce a comptime type for struct literals: fn foo(args: struct {a: u8, b: usize, c: []const u8}) void {}
test "optional argument names" {
foo(.{.c = "Hi!", .a = 0, .b = 42});
foo(.{.a = 0, .c = "bar", .b = 10});
} This would be the struct equivalent of tuples in the proposal to remove var args and add tuples: test "foo" {
var x: i32 = 1234;
var y = "blah";
std.debug.warn("int = {}, str = {}\n", [x, y]);
} Here whether the tuple syntax is |
For that comptime integer type wraparound arithmetic operations should be disabled (to avoid confusion like this: #964 (comment)). Also, what if I have my own function
The compiler would need to keep track on every immediate value, whether it still fits within valid range. |
+1 for named arguments. I agree I find mixing named and position (rearranging) argument gets confusing when reading code and should be avoided. One use of named arguments that I really like if dealing with boolean flags: foo(true, true, false, true);
// vs
foo(fullScreen: true, showMouse: true, logErrors: false, displayFps: true); For flags it would be nice to have comptime enum literials, but thats a different topic.
@BraedonWooding The optional argument name concept is interesting, but if you can give an argument a better name, then I would think thats what the argument should be. Self documenting code and such.. Also off topic for named arguments but, @andrewrk It would be interesting if the idea of comptime type for struct literals could also work for return types. Tuples may solve this as well, they would be better if they also support unpacking but thats a different discussion.
|
Just a random but related thought: in C99, I'm using structs with designated-init as a sort-of-optional-named arguments feature. It looks a bit weird and inefficient at first, but it's actually more powerful for complex cases, and the generated code doesn't look worse than having a function call with many arguments (which wouldn't fit into registers): // the function prototype would look like this:
sg_image sg_make_image(const sg_image_desc* desc);
// now in C99 you can embed the struct initialization into the function call,
// and only partially initialize the sg_image_desc struct (missing members will
// be set to 0, which I need to treat as 'default value' in the function call, because
// C99 doesn't let me define default values in the struct declaration):
sg_image img = sg_make_image(&(sg_image_desc) {
.width = 512,
.height = 256,
.num_mip_maps = 1,
.pixel_format = SG_PIXELFORMAT_RGBA8
}); The nice thing is that this also works for complex cases (e.g. arrays or embedded structs): sg_pipeline pip = sg_make_pipeline(&(sg_pipeline_desc){
.layout = {
.buffers[0].stride = 28,
.attrs = {
[0] = { .name="position", .format=SG_VERTEXFORMAT_FLOAT3 },
[1] = { .name="color0", .format=SG_VERTEXFORMAT_FLOAT4 }
}
},
.shader = shd,
.index_type = SG_INDEXTYPE_UINT16,
.depth_stencil = {
.depth_compare_func = SG_COMPAREFUNC_LESS_EQUAL,
.depth_write_enabled = true,
},
.rasterizer.cull_mode = SG_CULLMODE_BACK,
}); Of course on one hand this is just a workaround because C is missing optional, named args as well, but in the end I even prefer this solution. All in all, C99's designated initialization is the most convenient way for cases where a struct has many members, but usually only a few of them must be set to a non-default value. For instance, C++ has many ways for initialization, but none are as convenient for this case as C99 (at least not with tons of boilerplate code). In nim I was able to get close, but had to add a custom operator to partially initialize arrays, and additional 'constructor' functions: https://github.com/floooh/sokol-nim-samples/blob/master/cube.nim#L114 |
Solved by #485 (comment) + #685 |
Proposed syntax:
Invalid argument names obviously cause a compile error.
To match the arguments, we simply look at the named arguments first, then match the rest in the same order they appear in the function definition.
The text was updated successfully, but these errors were encountered: