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

[SUGGESTION] Named arguments are somehow similar to designated initializers #330

Closed
msadeqhe opened this issue Apr 8, 2023 · 6 comments
Closed

Comments

@msadeqhe
Copy link

msadeqhe commented Apr 8, 2023

If for example this is the syntax (similar to C++1) for designated initializers in C++2:

x: Point = (.x = 10.0, .y = 2.0);

Also the similar syntax can be used for named arguments in C++2:

y: std::vector<int> = (0, .count = 5); // (0, 0, 0, 0, 0)
z := func(.first = 1, .second = 2);

Named arguments help to distinguish function call on overload resolution (e.g. this issue about std::vector initialization), and they are more readable than positional arguments.

My suggestion is if someday C++2 supports named arguments, its syntax (it doesn't matter how it looks like) should be similar to the syntax of designated initializers.

Will your feature suggestion automate or eliminate X% of current C++ guidance literature?

Yes, less complex and uniform syntax will make C++2 simpler to learn and easier to remember.

@msadeqhe
Copy link
Author

msadeqhe commented Apr 8, 2023

I should mention that @hsutter in this commit already banned variable shadowing for typed scope functions. Therefore designated initializer doesn't conflict with constructor in the following code:

Point: type = {
    x := 0;
    y := 0;
    operator=: (out this, x: int, y: int) = { ... } // ERROR! It's banned.
    operator=: (out this, xarg: int, yarg: int) = { ... } // OK.
}

x: Point = (.x = 10.0, .y = 2.0);

@AbhinavK00
Copy link

AbhinavK00 commented Apr 8, 2023

Val has.a feature like this which is cool. This would also help eliminate ambiguity of contructors. We just need to settle on rules of using this.
Edit: Providing an example:

vec1 : std::vector = (.val = 42, .size = 5);  //(42, 42, 42, 42, 42)
vec2 : std::vector = (.arr = [42, 5]);  //(42, 5);

This is very easy to distinguish.

@msadeqhe
Copy link
Author

msadeqhe commented Apr 8, 2023

Yes, for vec2 it could be written like before: vec2: std::vector<int> = (42, 5);

Additionally with the help of parameter aliases (a variant of function aliases), we may change the name of parameters. This is useful when dealing with external APIs:

add1: (x: int, y: int) -> int = x + y;

// add2 is a function alias with parameter aliases.
add2: (a: int, b: int) -> int == add1(a, b);

res1: = add1(.x = 1, .y = 1);
res2: = add2(.a = 1, .b = 1);

The syntax doesn't matter, I just wanted to share how function aliases can improve named arguments if C++2 supports them.

@filipsajdak
Copy link
Contributor

Herb commented on named arguments here: #202 (comment)

@msadeqhe
Copy link
Author

msadeqhe commented Apr 8, 2023

Thanks, that's what I've found:

Do you already have a plan in mind for the syntax of designated initializers, @hsutter ? That might be what "forces" CPP2 to use { } for lists and aggregates anyway.

I've been deprioritizing them because they're not addressing one of the pressing problems with C++ and so can be looked at later. When I do look at them, I plan to consider them together with named arguments as a general feature, and avoid doing something special for constructors that doesn't work the same way for other function calls. So I don't think named arguments will be related to a brace syntax, if I do add them in the future for all functions arguments (not just constructor arguments).

I hope that means yes, the concept of named arguments and designated initializers will be unified 😁

@hsutter
Copy link
Owner

hsutter commented Apr 9, 2023

Thanks! If I do pursue this path in the future I'll definitely have an eye on making it a general feature that works well across the space of named initialization cases.

However, I'm going to close this as out of scope for now, as doing it right to work well with existing libraries would require at minimum fully parsing Cpp1 (and at least do name lookup and overload resolution) and even then wouldn't generally work the way you want.

This line you mentioned above illustrates some of the problems:

y: std::vector<int> = (0, .count = 5); // (0, 0, 0, 0, 0)

Consider what it would take to try to support this code:

  • It would require that cppfront compile Cpp1 <vector> etc.
  • It would not actually work for this example (at least not with that name and not in portable code) because implementations are not required to call the parameter count and the name can vary across implementations. For example, the MS STL vector calls it _Count.
  • It wouldn't work well for Cpp1 libraries in general, because Cpp1 allows naming the parameters differently on declarations and definitions (and specializations...) and then the compiler would have to decide which name to use.

It's possible that this feature could be supported for Cpp2 code only, where we can avoid the third bullet's problem since there are no forward declarations. But even then it would require quite a bit of work for cppfront to do things it doesn't do yet today. So I'll keep this in kind, but probably only for Cpp2 code, and probably not until quite some time in the future. Sorry, but maybe someday!

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

No branches or pull requests

4 participants