Replace Point { x: 3, y: 5 } with Point { x=3, y=5 }

I would like Point { x => 3, y => 5 }, which is similar to Scala’s map syntax

val band = Map("Dave" -> "Bass",
               "Tony" -> "Guitar",
               "Greg" -> "Drums")

This is a consequence of constructor-follows-declaration – tuple structs/variants have their constructor/declaration in a value-like form struct S(uint); S(5), with types inside parentheses like a method call (instead of within angle brackets, like all other type parameters), while dictionary-structs use the type form S { a: uint }; S { a: 5 }, with types and values after a colon.

2 Likes

+1 I like C99 syntax, and to me it’s assignment, so similarity between struct.x = 1 and Struct{x = 1} makes sense.

Also I have to press shift for :, but not for = :slight_smile:

1 Like

I’m surprised this change wasn’t accepted, : syntax is inconsistent

No, it’s not. See two posts above your post.

S { a: uint }; doesn’t make sense either, it should be S { a => uint }; because we’re not doing type ascription to a local called a

I actually like => in record/struct types because it is not ambiguous and doesn’t interfere with type ascription

I really like @glaebhoerl's Point { .x = x, .y = y } syntax, as I've said on the rust-lang/rfcs issue:

I'd never seen that syntax before in the context of Rust and I kinda like it, I wish we had this discussion before the alpha (is it really too late for miracles?). It would fit well in with a likely expansion of move semantics:

Point { .x = 10, .y = 11 }
// would expand to the more verbose
{ let p: Point; p.x = 10; p.y = 11; p }
// even if that would be safe, I doubt it will be overused as the
// struct literal syntax is always shorter - except if this worked:
{ let p: Point; (p.x, p.y) = (10, 11); p }
// but why not
Point { (.x, .y) = (10, 11) }

We can still change this... right?


Which leads to a further extension - if we had IndexSet:

HashMap { ["foo"] = bar }
// as sugar for:
{ let m = HashMap::new(); m["foo"] = bar; m }
1 Like

I’m definately against =, because it would imply that there’s assignment happening somewhere, where it’s not. The inconsistency with type ascription could be resolved by using different syntax, like =>, but I don’t think it’s a big issue.

The assignment would make sense only if we already had a struct variable and wanted to assign few fields at the same time (similar to post above):

let mut p = Point {x: 1, y: 2};
p {.x = 0, .y = 0};
let mut vec = get_a_list_of_strs();
vec {[0] = "first", [1] = "second"};

Summing up: Only use = where actual assignment is taking place.

Assignment doesn’t really happen anywhere either. If I wrote let x = 5; it may or may not store that value anywhere. Most likely, x will be replaced by 5 once the code is generated.

We’re talking about how the language specifies it. = is an assignment operator right now, in Struct { a: 5 } no assignment happens from the perspective of the language, it’s just specifying a possible value of the struct.

Yeah, but if you do the Point { .x = 3, .y = 5} syntax it will be a “structured assignment”

let point = Point { .x = 3, .y = 5} converts into let point = {let p: Point; p.x = 3; p.y = 5; p};

similarly if you have a let p: Point; then you can do let point = p { .x = 3, .y = 5 }; which desugars to let point = { p.x = 3; p.y = 5; p}

I’m against changing the syntax. I think the syntax as it is now is the least surprising and don’t find the overloading of : to be any more offensive than the overloading = would be.

I love the symmetry we have now with struct definition, construction, and deconstruction via pattern match:

struct Point {
  x: u8,
  y: u8
}
let p = Point { x:3 , y:5 };
let Point { x:a, y:b } = p;
println!("x was {}, y was {}", a, b);

I recall a time recently where I was out of study, and I just took a guess at the syntax and found that it met my expectation exactly; so the “it’s inconsistent” argument is at least subjective, I would argue.

3 Likes

type ascription would let you do let Point { x: a: i32, y: b: i32} = p which raises the question of operator associativity

the compiler has no problem with this, but I do

let Point { .x = a: i32, .y = b: i32} = p looks subjectively better to me

2 Likes

I suppose if I had to pick one of the two syntaxes in your comment for type ascription I would agree. The double colons in let Point { x: a: i32, y: b: i32} = p are rather ugly.

I don’t like the .x = at all, however. Isn’t the . superfluous? We already have the context that we are talking about the struct’s fields because of the surrounding Point { ... }.

Syntactically, yes. (Syntactically, we could probably even lose the = / :.) It might be helpful for a human reader, especially in patterns.

This syntax is definitely growing on me.

I kind of like being more explicit. Let’s say Rust 1.8 or some other 2017 version adds structural records so you can do this:

let point = { .x = 3, .y = 5};

this would actually conflict with blocks, but the .x disambiguates it. You can emulate keyword arguments if your function takes a structural record:

drawRectangle({ .coords = { .x = 50, .y = 10 }, .dimensions = { .width = 150, .height = 120 }, .color = { .red = 1.0, .green = 0.0, .blue = 0.5 }});

the signature of the function being

fn drawRectangle(keywords: { .dimensions = { .width: i32, .height: i32 }, .coords = { .y: i32, .x: i32}, .color = { .red: f32, .green: f32, .blue: f32}})
2 Likes

The more I think about this, especially as it relates to type ascription, the more important I think it is that this be changed.

+1 for Point { .x = 3, .y = 5}

3 Likes

Yeah, when I saw that post, I was really confused how you get a variable named Bar when it was clearly a type, but then I realized it’s inside the struct…

I had to ask on IRC how it worked. It’s like a pattern in the parameters, and since you can have : in signatures for both types and patterns it’s really confusing

2 Likes

+1 to Point {.x = 3, .y = 5}, the fact that this syntax is in sync with C99 is also a plus.