Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upChange the syntax of struct literals to use `=` #65
Conversation
This comment has been minimized.
This comment has been minimized.
|
Also makes it easier for tools to distinguish struct definitions from struct literals. |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
SiegeLord
commented
May 4, 2014
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 comment has been minimized.
This comment has been minimized.
|
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 } |
This comment has been minimized.
This comment has been minimized.
|
@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 |
This comment has been minimized.
This comment has been minimized.
|
@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 |
This comment has been minimized.
This comment has been minimized.
dobkeratops
commented
May 4, 2014
|
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 comment has been minimized.
This comment has been minimized.
SiegeLord
commented
May 4, 2014
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 |
This comment has been minimized.
This comment has been minimized.
|
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, |
This comment has been minimized.
This comment has been minimized.
pczarn
commented
May 4, 2014
|
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. |
This comment has been minimized.
This comment has been minimized.
|
@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 |
This comment has been minimized.
This comment has been minimized.
|
@pcwalton I would note about other languages that those which use |
This comment has been minimized.
This comment has been minimized.
|
You create a reference with On Sunday, May 4, 2014, Nick Cameron notifications@github.com wrote:
|
This comment has been minimized.
This comment has been minimized.
|
@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. |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
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 comment has been minimized.
This comment has been minimized.
cloudhead
commented
May 6, 2014
|
This is one of the first things that surprised me with Rust. I expected the assignment to work with |
This comment has been minimized.
This comment has been minimized.
|
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. |
This comment has been minimized.
This comment has been minimized.
|
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. |
This comment has been minimized.
This comment has been minimized.
|
@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. |
This comment has been minimized.
This comment has been minimized.
|
@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. |
This comment has been minimized.
This comment has been minimized.
|
@bstrie Hmm, ok. This |
This comment has been minimized.
This comment has been minimized.
dobkeratops
commented
May 6, 2014
|
..and if thats the case, throwing the idea out there, might disambiguating mutation be the lesser evil (:=, F#'s <- ..or perhaps mut expr=expr... |
This comment has been minimized.
This comment has been minimized.
|
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.) |
This comment has been minimized.
This comment has been minimized.
|
I guess people who like the status quo interpret |
This comment has been minimized.
This comment has been minimized.
|
@kballard I think the fact that we are relying on finding |
This comment has been minimized.
This comment has been minimized.
|
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 ( |
This comment has been minimized.
This comment has been minimized.
SiegeLord
commented
May 8, 2014
|
Is the implicit claim here that resolving @huonw's point about parsing initializers with |
This comment has been minimized.
This comment has been minimized.
|
@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 comment has been minimized.
This comment has been minimized.
|
I don’t see any potential ambiguity arising from this — |
This comment has been minimized.
This comment has been minimized.
|
@nick29581 You seem to be just hand-waving when you say that the ambiguity with @P1start |
This comment has been minimized.
This comment has been minimized.
|
@kballard I hadn’t considered that. This is the only time I’ve actually wanted C-style brackets around the conditions in |
This comment has been minimized.
This comment has been minimized.
|
@P1start Struct initializers never return bool, but the parser doesn't know that. And the same problem affects |
This comment has been minimized.
This comment has been minimized.
|
@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 |
This comment has been minimized.
This comment has been minimized.
|
@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. |
This comment has been minimized.
This comment has been minimized.
|
Trying to define |
This comment has been minimized.
This comment has been minimized.
|
One option would be being greedy, so |
This comment has been minimized.
This comment has been minimized.
|
@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 |
This comment has been minimized.
This comment has been minimized.
|
The mistake is not that Fundamentally, as long as our struct literals look like |
This comment has been minimized.
This comment has been minimized.
|
@huonw That's actually not a terrible idea. And it would work just as well with the current |
This comment has been minimized.
This comment has been minimized.
bill-myers
commented
May 8, 2014
|
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 |
This comment has been minimized.
This comment has been minimized.
|
@bill-myers That rather strongly violates the principle that type initialization should look like type declaration. |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
@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 |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
@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 |
This comment has been minimized.
This comment has been minimized.
dobkeratops
commented
May 11, 2014
|
@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 :) ) |
This comment has been minimized.
This comment has been minimized.
|
@dobkeratops oh, I'm sorry, I misread. I would be very much in favour of that - I prefer |
This comment has been minimized.
This comment has been minimized.
|
@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. |
This comment has been minimized.
This comment has been minimized.
|
@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. |
This comment has been minimized.
This comment has been minimized.
|
-1 to changing assignment syntax solely to solve this papercut, and -1 to multi-token symbols to replace |
This comment has been minimized.
This comment has been minimized.
|
That said, if we ever happened to ditch immutability-by-default for whatever reason, requiring |
This comment has been minimized.
This comment has been minimized.
dobkeratops
commented
May 12, 2014
|
@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 . |
This comment has been minimized.
This comment has been minimized.
|
Closing. It's very late to be changing this and the benefits aren't overwhelming. |
nrc commentedMay 4, 2014
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.