-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Changing Struct Literals #841
Conversation
y: i32, | ||
} | ||
|
||
let Point{ x: i32 => first, y: i32 => second} = Point{ x: 1, y: 2}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I thought of it would look like:
struct Point {
x => i32,
y => i32,
}
let Point{x => first: i32, y => second: i32} = Point{x => 1, y => 2};
But in general, we are on the right track with this RFC.
You could throw some assert!
s here and there to show what is the resulting state.
assert!(first == 1);
assert!(second == 2);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the way it's written in the RFC. In terms of judgements, it's pretty natural to think of x: A = y
as x: A
followed by x = y
. The other way around is less clear. Should it be interpreted as (x = y) : A
or x = y
followed by y: A
or like the original but reversed: x = y
followed by x: A
? Also, there's precedent with let x: A = y
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're only confused, because you still don't see the difference between an assignment and a struct literal and using =
doesn't help.
Structs in patterns are defined as something like this (changed :
to =>
for sake of clarity):
pattern ::= StructName "{" (field_name "=>" pattern)* "}"
And then type ascription RFC extends pattern with pattern ::= pattern ":" type
That's why it should go {field => variable: Type}
. It's in line with the current type ascription RFC.
I think that the design constraints should be moved to the motivation section. Additionally, alternative syntaxes should be in the alternatives section (maybe as a list comparing the proposed designs). The "detailed design" section should only contain exactly one syntax design, the one that you prefer. Putting things in logical places makes it easier to read the RFC. |
+1 to the |
Another 👍 to the |
I prefer the syntax proposed by @phaux : Note that the syntax that uses |
I'm generally in favor of the C99 syntax (with or without dots), but I don't believe it can be accepted given that abiding the 1.0 timeline is treated above everything else. |
@petrochenkov there is a new schedule for 1.0 http://blog.rust-lang.org/2015/02/13/Final-1.0-timeline.html |
@theemathas do note this important section of that blog post:
|
@pnkfelix I was also opposed to changing the syntax, but it turns out it would make sense to change it, bacause it clashes with some features planned for post-1.0. |
@petrochenkov, I think this is a simple syntax change that can be introduced along with a deprecation period for the old syntax, as both can coexist for a while. So if it is accepted, we have enough time to settle on the new syntax. @theemathas, I agree in patterns
@pnkfelix, thanks for the reminder. The biggest problem with the current struct syntax is that with type ascription, there will be ambiguities. Is I remember avoiding such ambiguities is one of the reasons that |
@CloudiDust I am also OK with another syntax if you don't want However, I think that the |
(my comment was not meant to be taken as an argument against this proposal; it was more a knee-jerk reaction to the two comments preceding it.) On its face I actually have no problem with inserting a period before field names, i.e. By the way, here is an unresolved question the RFC might pose: should the pattern binding syntax now be |
I am 👎 on making such a big change at this point in development, and also, on the specific changes itself. I strongly prefer the current syntax. |
There's also another flaw in reasoning of the proponents of designated-initializer-like syntax. // a Point struct is being assigned to the variable p
// there is a single assignment and one `=` operator
let p = Point { x => 0, y => 0 };
// this is a sugar for two assignments and we have two assignment operators
p { x = 0, y = 0 };
// this desugars to
p.x = 0;
p.y = 0; They're appropiate for Rust in general, but they shouldn't replace struct literals, bacause they serve different purpose. This is a tiny detail that most people don't realize.
With |
@theemathas, I think all alternatives will have their own inconsistencies somewhere so this is about subjective preference. But compared to inconsistencies, ambiguities are more objective problems, which I believe should be addressed no matter which alternative we choose. @pnkfelix, I am not sure which one to prefer, on one hand, @steveklabnik, if we can find a non-hackish way to deal with the ambiguities that will be introduced by type ascription, then I am also fine with the current syntax. |
@steveklabnik We all want type ascription and to keep current struct syntax, but unfortunately we can't have both. |
@CloudiDust please note that I was talking in my proposed question about patterns, not expressions. I do not see the expression |
@pnkfelix How do you propose to write a struct pattern? How do you propose to write a struct expression? |
@theemathas as I said in the comment, either (For the shorthand when the pattern is just an identifier that has the same name as the field, I assume we would continue doing But I was really just trying to post a point to the RFC author, not cause extensive bikeshedding on a relatively minor detail. |
@pnkfelix, sorry for the typo, I mean Currently I slightly prefer However, given that this is a quite subjective matter, I hope we can find a way to have both the current struct syntax and type ascription without future hacks. |
@phaux I'd take the struct literal syntax over ascription. |
@CloudiDust @steveklabnik Do you two mean something like |
@steveklabnik I was thinking the same way, but then I realized that keeping the syntax would also close the door to much more features that we would want in the future. Think about it, it's just a syntax, but it limits the possibilities so much. The |
@theemathas No, I mean: let x = Foo { .bar = 1 };
let Foo { baz = .bar } = x; // Now local variable `baz` has value 1. But I think this is not very pretty either. Also I believe you mean @pnkfelix, not @steveklabnik. |
I'm also -1 on changing the syntax. I think it's good now and type ascription is not needed so often that it should govern a change to struct-literal syntax. Please correct me if I'm wrong but I believe the naive syntax for type ascribed struct literals is at least non-ambiguous and useable: Foo { x: a: Bar, y: c: Baz } Whether it is pretty is certainly up for debate... though I think the time for that is long past. On the bright side we can make this prettier with tools like syntax-highlighting and conventions. For example removing the spaces around the ascribing Foo { x: a:Bar, y: c:Baz } Or if you really feel like it's too confusing put some parenthesis around the ascribed expression: Foo { x: (a: Bar), y: (c: Baz) } |
@CloudiDust what about |
@theemathas Oops. I believe if we do Maybe we should allow both after all? (Looks like it's going out of control.) @jakerr, there will be a parsing ambiguity with I am wondering if it is possible to tweak the current struct syntax a little so |
Well that's a great way to stop the discussion of alternatives. |
For example, you could use the current syntax: WindowSettings {
title: "Hello world!".to_string(),
samples: 0,
size: [300, 300],
fullscreen: false,
exit_on_esc: true
} and WindowSettings {
title, samples, size, fullscreen, exit_on_esc =>
"Hello world!".to_string(), 0, [300, 300], false, true
} Named argument syntax would be similar, and allow type ascription with foo(x: 3, y: 4)
foo(x, y => 3, 4)
foo(x, y => 3: i32, 4: i32) |
I think that there's no need for introducing such complicated syntax, but I don't have strong opinion on this one. I propose: Point3D { x, y, z =>> point2d.x, point2d.y, 0 }
// shorthand for
Point3D { x => point2d.x, y => point2d.y, z => 0} Anyways, this will need a separate RFC, so we can discuss it later. @bvssvni I would rather like to get rid of |
@bvssvni, I'd prefer abandoning the current literal syntax and aim for more consistency if we are to introduce the @phaux, I am in favor of introducing Also, both |
I wrote another RFC: #866 |
team discussed struct syntax at weekly meeting. @pnkfelix attempted to present the most conservative change being proposed by the RFC (namely C99-style adding leading periods to field names and then using response seemed unanimously opposed to changing the struct syntax, and the argument was not solely based on schedule; @pcwalton argued largely based on precedent set by other languages, e.g. JS, which is also adding type ascription via So I think that this RFC is likely to be simply closed. |
@pnkfelix I'm reading through the old RFC of why |
@pnkfelix After a quick read-through, it seems the old RFC was rejected mainly because of 1) a parser ambiguity and 2) it was too late. Some ideas was suggested to solve the parser ambiguity, but I'm not capable to tell whether it is solvable. My major concern is the conflict between named argument syntax and type ascription. I don't see this discussed much and would appreciate this being settled before 1.0. It is not the end of the world, but it sticks out as part of the language that "doesn't feel right". At this point, things have been relatively stable, so I don't think going through one extra round of upgrading is a big deal. I'm for changing this, probably not to |
@bvssvni all I can tell you is that most of the core team members were present at the weekly meeting ; some were strongly opposed to changing the syntax (and obviously did not think that using |
I've read through the comments and the RFC once more and made up my mind. +1 to the This syntax can later be extended to @eddyb 's idea with tuples. It solves the ambiguity problem. It also works well with auto complete in text editors, which is often trigger by One question: Why are JS used as argument for keeping the syntax, but C99 extension against? They are both precedences but no reason is given why one is good and the other is bad. I think the use-follows-declaration rule seems a bit artificial, as I think of it as simple assignment and then Rust is still a great language as it is, but if I imagine myself in a world without pressure of releasing it then I'm in favor of this RFC. Of course the core team got my full sympathy. It would be surprise if this went through so close to 1.0, but thanks to @iopq for writing this up! |
I am strongly in favor of changing struct literals (without changing struct definitions). I realize there are trade-offs, consistency-wise, but by far the most consistent seeming to me is to use I don't think what JS, Ruby, and Python do is important here. They are all dynamically-typed languages, and don't have important (and likely ambiguous, with type ascription) other uses for them. They're also not an area that Rust is targeting. It would be very nice to allow the type of struct literals to be inferred in the future, and even to have anonymous structs. Neither of these would be possible using if struct syntax stays the same and type ascription is introduced. Type ascription is important, and Thus, I find it very important to change struct-literal synax, regardless of what syntax is chosen. That said, by far my favorite syntax is
Ideally, this would be the only supported syntax, but since 1.0 is fast approaching, and there is a strong desire not to break the world, the old syntax could be retained and deprecated, with the new syntax preferred. Potential new features such as inferred struct literals would require the programmer to use the new form to avoid ambiguity. (This could even be done post 1.0) Also, to respond to @pcwalton's comment that "Even JS has gone with |
Today's Rust also uses |
@steveklabnik inthat case the name to the right of the colon is still type-level, not value-level, correct? |
@steveklabnik It would be still more consistent for @pcwalton Typescript uses |
It's still in the context of types. Using |
@rkjnsn, I propose another syntax: (If an identifier is prefixed by It has the following advantage compared to
Disadvantages:
But I think |
@CloudiDust I strongly suspect those who object to switching syntax are not going to see From what I can tell, this seems to be about some sort of inertia (i.e., objections about "so much churn!") and/or attachment to Javascript style syntax (perhaps based on the recognition that the latter is familiar to a very large population of modern programmers). (Regarding whether this situation is analogous to what we went through with |
@pnkfelix, the The change is simply adding Also, the latter two alternatives are (more) heavier weight, and people may dislike the loss of a lightweight syntax. But I can see why people may still say no to this change though. Examples are in the comments of #866. |
If the sole reason for wanting this change were "this other syntax looks slightly prettier", then I'd agree that it would be a pointless change at this point. However, it has many more advantages, as I outlined above. |
I tried to come up with an RFC for The theoretical advantages of the alternatives may not actually translate into practical advantages. |
I discovered that optional arguments through struct sugar conflicts with Then there is a problem with baking in optional arguments into the language. Part of the motivation to have named argument syntax is optional arguments, but since
Leaving out an optional argument when calling a function is different than passing Since optional argument has slightly different semantics than If we don't plan to add optional arguments, some of the motivation to have named arguments falls away, and therefore some of the motivation of changing struct initialization syntax. We might still benefit from changing to We might just keep |
@phaux That looks nice! The idea won't work for named argument syntax, because all the arguments must be treated as an anonymous struct that implements There are slightly changes in the semantics here that makes a huge difference for refactoring. It destroys the 1:1 mapping between struct initialization and optional arguments. You have to think of the arguments as a struct, not as ordinary optional parameters. The alternative is baking it into the language, but that would collide with current practice of The old struct sugar RFC solved this problem, but now that we get ambiguity with either type ascription or Therefore, we might as well just keep |
@CloudiDust It's true that |
@rkjnsn, personally I think the loss of succinctness is acceptable (and the |
Sadly, changes to struct literal syntax at this stage are not possible. Even if there were a perfect new syntax, the level of disruption at this late stage would be hard to justify. In particular, there is not any technical clash with type ascription, only potential confusion. Since type ascription should be rare, that does not justify such a large change. There are also many people who like the current syntax (not me, actually, I much prefer |
i get the “too low gain/disruption ratio” argument, but there’s one thing i don’t get:
could you tell us what the problem with the following syntax is and how it is not widely approved? struct Point { x: u8, y: u8 }
// or
struct Point { .x: u8, .y: u8 }
// …
let p = Point { .x = 5, .y = 10 };
let Point { a = .x, b = .y } = p; |
Regarding "widely accepted", I know for myself I have largely ignored this On Fri, Feb 27, 2015, 4:13 AM flying-sheep [email protected] wrote:
|
While this affects the type ascription RFC, it is a good thing to do even if type ascription is not implemented until later. Other considerations are raised like record types and keyword argument syntax.
(rendered)