-
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
Change the syntax of struct literals to use =
#65
Conversation
Also makes it easier for tools to distinguish struct definitions from struct literals. |
Actually, one alternative I didn't think of earlier is that we could reverse the order of field and variable in patterns, so we would write |
I'm not sure what you mean, the difference is the presence of the I disagree with this RFC because it breaks the symmetry between struct declaration, pattern and initialization. The pattern syntax of |
This possibly causes some confusion: for foo in S { x = 1 } { y = 2 } There's two possible parses: for foo in (S { x = 1 }) { y = 2 }
// or
(for foo in (S) { x = 1 })
{ y = 2 } |
@SiegeLord I'm not saying there is a problem, just that it would be even easier. I would be easier because you currently you need context - are you surrounded by an struct/enum block. With the proposed change, you don't need that context. This only breaks the symmetry between declaration and (pattern and initialisation). I think that is a good thing because they are very different concepts. The declaration is Note that in exchange we get symmetry with variable assignment and field assignment. In the first case because we declare variables in the form |
@huonw I think this is solvable by generalising struct initialisers. That is, we always use the second parse and unify block syntax with anonymous record initialisers - all assigned to free variables in the block end up as forming a record which is the result of the block and which must be unified with the contents of the named struct. This may be bordering on the crazy, but we would need to solve this problem if we allow generalised type ascription or for initialising virtual structs if we go down that road. Put another way, the fact that we are parsing struct literals based on whether or not there is a |
maybe wild suggestions... I realise these aren't pretty, but here goes.. S{ .a=expr, .b=expr..} // like C99 designated initializers or use := somewhere - either for variable mutation ? or for field initialisation.(unfortunately it would be the opposite of 'go' if it was mutation.) Is local variable mutation the less likely case- with rusts emphasis on declaring things initialised , & expression oriented syntax? or would it annoy people from other languages too much. (I don't think it would annoy me, I appreciate the ideas that mutation should stand out, and creating initialised should be more common) Of all those I think I prefer 'mut x=..' but don't know what other problems it would might cause.. if mutation was separated from initialisation, would it make it easier to do keyword arguments in any future version? ..or is it possible that less ambiguity between a block with assignments and a struct initialiser would let you just write field initialisers without having to specify the struct name..., making it easier to use structs inplace of keyword arguments. (don't need to write the struct name, it gets implied from the context..) |
This symmetry exists in every other type today, so it's always 'misleading'. I don't find it to be a problem at all.
I don't think those things are related enough to field initialization to require symmetrical syntax. In return for this tenuously important symmetry, we get a confusing order for struct patterns which I think more than outweighs any gains by this change. I should also note that keyword arguments would have a natural correspondence to struct fields, and thus could use |
Generally, one of Rust's principles is that declaration follows use. I'm not a huge fan of this change because we'd be losing the symmetry between declaration and initialization. Furthermore, |
I don't like either of the proposed pattern syntaxes. I believe the meaning of I happen to like this syntax proposal. Since we are starting to mention other languages, take a look at Lua. |
@SiegeLord @pcwalton I don't agree that in Rust "declaration follows use" or that "This symmetry exists in every other type today", in fact structs are pretty much the exception: tuples - yes, declaration follows use, but there are no names to use in the declaration or use, so hard to see how you could do otherwise |
@pcwalton I would note about other languages that those which use |
You create a reference with On Sunday, May 4, 2014, Nick Cameron notifications@github.com wrote:
|
@SiegeLord I do not think the connections are "tenuous". Field assignment is setting one field of a struct, struct initialisation is setting all the fields of a struct. Variable initialisation is initialising a piece of memory, so is a field-entry in a struct literal. |
What I really meant was "the type syntax follows the initialization syntax". Unfortunately the common phrase for that is "declaration follows use", which is not really accurate. This applies for functions as well in Rust: the type syntax is
Well, ML forgoes this, in an explicit rejection of type-syntax-follows-initialization-syntax: the type syntax for a tuple |
OK, Oh, wow, the ML syntax is certainly different :-p Even in the C tradition, it has become weaker with time. C was very strongly about type declarations following use. C++ less so (e.g., not requiring the |
This is one of the first things that surprised me with Rust. I expected the assignment to work with |
I disagree with this proposal. Variable assignment is, well, assignment. But fields in struct initializers are declarations of value, not assignments of value. I also agree with @pcwalton about type-syntax-follows-initialization-syntax. |
I'm mostly indifferent to this proposal. I'd be happy with either today's The ambiguity mentioned by @huonw is a legitimate concern. Please add a mention to this in the RFC, along with your proposed solution. Ultimately it seems that the fate of this RFC hangs on the long-hypothesized feature of generalized type ascription. Depending on how that turns out, this may be a genuine backwards-compatibility concern. I vote that we suspend judgment on this RFC until an RFC for generalized type ascription is written up and discussed. |
@bstrie What's the backwards-compatibility concern with type ascription? The only potential issue I can think of is a slight ambiguity when parsing Granted, having any ambiguity at all is bad from an idealistic standpoint, but I think this is a rather minor case. |
@kballard , I don't know what the backcompat concerns are, nor can I, because nobody's ever written up a proposal for it. I'm not comfortable claiming that a new feature probably won't make our grammar ambiguous. And if generalized type ascription does introduce an ambiguity with our current struct literal syntax (again, I have no idea!), then I personally see no philosophical reason to be against this proposal. |
@bstrie Hmm, ok. This |
..and if thats the case, throwing the idea out there, might disambiguating mutation be the lesser evil (:=, F#'s <- ..or perhaps mut expr=expr... |
Changing this would lose quite a bit of similarity between struct declaration and struct instantation... Currently it's With this proposal it'd read
In this example, no assignment is going on, still a (My thoughts on this.) |
I guess people who like the status quo interpret |
@kballard I think the fact that we are relying on finding |
To make the general type ascription thing a little bit more concrete and less of a straw man, I lay out how I think it should work. Note that this isn't definitive in any way nor a proper proposal for it. I think the idea is that anywhere an expression is accepted in rust code ( This makes using patterns a bit cleaner. Some formal syntax for let (match would work similarly):
Note that there is no special case in let for Using this, the following example would be legal (but kind of pointless):
The problem is with struct literals: 'S { x : t }' Should this be parsed as a struct literal or a variable name ( |
Is the implicit claim here that resolving @huonw's point about parsing initializers with |
@nick29581 Patterns aren't expressions. So your assertion that As for parsing struct literals, the ambiguity you mention is the same one I mentioned earlier. But my expectation is that the chance of someone writing @SiegeLord @huonw's point was that parsing initializers with Which is to say, I think changing struct literals to |
👍 This makes the structure initialisation syntax more consistent with everything else IMO. I don’t see any potential ambiguity arising from this — |
@nick29581 You seem to be just hand-waving when you say that the ambiguity with @P1start |
@kballard I hadn’t considered that. This is the only time I’ve actually wanted C-style brackets around the conditions in |
@P1start Struct initializers never return bool, but the parser doesn't know that. And the same problem affects |
@kballard Yeah, it’s futile for me to continue to try to find a way for this to work. I’d like to know what @nick29581 has in mind, though. I just think that keeping struct initialisers with |
@kballard if I appear to be hand waving, it is because I am :-) Like I said, I don't want to spend time working it out if this is not going anywhere. A simple solution would be that for and if expressions only take a subset of expressions before their blocks and that subset excludes struct literals (given that it doesn't make much sense to use a struct literal in either place, we don't lose anything, and if you really wanted to put one there you could use brackets). I expect you could do this to resolve any ambiguity with I was thinking of something more complicated wrt generalising the struct literal which would mean defining a struct literal as just a name and a block and extracting the field values from the block, rather than making a struct literal its own syntactic construct, but I think that is neither necessary nor sufficient, actually. |
Trying to define |
One option would be being greedy, so |
@kballard it is not as big a hack as looking into an expression to check for the presence of an Really, the mistake is in the formulation of |
The mistake is not that Fundamentally, as long as our struct literals look like |
@huonw That's actually not a terrible idea. And it would work just as well with the current |
That could be fixable by using One could also then possibly eliminate the field names and switch to the Scala model where all structs are initialized using |
@bill-myers That rather strongly violates the principle that type initialization should look like type declaration. |
On Wed, May 07, 2014 at 10:18:27PM -0700, Kevin Ballard wrote:
The answer is that we would define a subset of expressions that can |
On Wed, May 07, 2014 at 11:23:01PM -0700, Huon Wilson wrote:
I'd be inclined to bias the other way. Which is more common: iterating |
@nikomatsakis With the proposed That said, defining a subset of expressions that excludes struct literals is a reasonable course of action. I know I said it was a hack earlier, but I'm coming around. Of course, if we do that, then I think we also need to expose this new expression type to |
I'm sympathetic to some of the anti-= arguments here - in particular that the ordering becomes weird in patterns and that in both cases it is not quite assignment. However, I still really dislike Any new symbol must not be directional since that would have the same problems of odd directionality in patterns (which means |
@nick29581 Why do you really dislike My view is that right now we have the two forms This also preserves the semantic meaning of struct Foo {
a: int
} declares a type wherein the slot Type ascription using |
@nick29581 One of my suggestions was to change mutation to := <- or even "mut lhs=rhs" .. to free up "=" to always mean binding/initialization (let, struct initialisers, patterns and maybe eventually keyword args :) ) |
@dobkeratops oh, I'm sorry, I misread. I would be very much in favour of that - I prefer |
@kballard pretty much. I dislike Thinking of Getting a bit more fundamental, or hand-wavey, depending on your point of view, I think the language of expressions (which includes values and variables) and the language of types in a programming language are distinct and should use different syntax. My unease around struct literals and the dissonance we would have with type ascription are symptoms of violating that principle. |
@nick29581 Depending on your point of view, the current format is about having nearly the same syntax for structs and struct instantiation, which would always be violated if you choose to use different symbols for As you can see I parse the
So I think it's reasonable to have different symbols for these two. |
-1 to changing assignment syntax solely to solve this papercut, and -1 to multi-token symbols to replace |
That said, if we ever happened to ditch immutability-by-default for whatever reason, requiring |
@nick29581 >>" I guess it would look a bit odd when you gave a type in a let expression (let x: int := 5)" .. the idea was that would still just be 'let x:int =5' - because its an initialization, not a mutation. use the context of let . |
Closing. It's very late to be changing this and the benefits aren't overwhelming. |
Fix an off-by-one in the count to send shutdown messages. Closes rust-lang#65
Deprecation warning handlers
Seeing that far-reaching and controversial syntactic changes seem to be in fashion at the moment, here is my pet peeve formulated as an RFC.