Idea: puns in simple patterns

But auto ref/deref may work for Foo { bar } but it does not work for Foo { mut bar }.

It would be cool to see Foo { &bar, &mut baz } but I wonder what would happened to Foo { bar? } or Foo { baz.await } or Foo { bar.field }?

That’s why I like @petrochenkov’s proposal from above, namely that we do a transformation like this:

Given a struct Foo defined like this:

Foo {
  field0: T0,
  field1: T1,
  ...
  fieldN: TN,
}

and the following struct literal:

Foo { expr0, expr1, ..., exprN }

where the only identifier in expr0 is field0, in expr1 is field1, …, in exprN is fieldN, then we desugar to the following struct literal:

Foo {
  field0: expr0,
  field1: expr1,
  ...
  fieldN: exprN,
}

I can very easily see that leading to errors. Consider math on a vector or matrix that wants to intentionally shuffle around components, for instance.

Also, just to confirm, would “one identifier” rule out dotted expressions like this?

struct V3 { x: f64, y: f64, z: f64 }
fn shuffle(v: V3) -> V3 {
    V3 { v.y, v.z, v.x }
}

I can easily see a C programmer writing that, because C allows initializing structs positionally.This needs to continue producing an error, rather than incorrectly producing an identity function.

I can easily imagine the same kind of error with expressions that have only one identifier.

(Even for the existing field punning, I can imagine code that will erroneously compile; I’d favor having, for instance, a lint for cases that involve structs containing entirely fields of the same type and same-length short names where the field puns appear out of order.)

6 Likes

I actually made this error with the existing shortcut once.

I needed to swap two fields and wrote something like this:

let s = if lo <= hi {
    S { lo, hi }
} else {
    S { hi, lo }
}
9 Likes

I can see at least two ways we could catch that with a lint.

The least likely to cause false positives: if you write two struct initializers with field puns in the same function with fields in different orders, lint.

Also, the one I mentioned in the previous post involving an out-of-order struct initializer with field puns that consist entirely of fields with the same name-length and same type. That could lead to false positives, but you can trivially fix those by reordering the fields or by labeling the fields.

4 Likes

It’s apparent that this can cause bugs regardless of what is proposed here, so it’s perhaps not very relevant to this discussion. At least, I don’t see how this proposal makes that situation any worse.

It seems to me that allowing arbitrary expressions (with only the “one identifier” limit) makes bugs more likely.

1 Like

My thinking is to disallow the use of dot expressions or keywords. We could also disallow non-unary operators. I think with all of these restrictions we can still improve ergonomics for the most common cases.

I do like the idea of a lint, though.

While I don’t personally have a use for it, I don’t have any strong objection to allowing this for most unary operators, if that would help.

I would find it quite confusing to permit &, though, precisely because of potential confusion with what ref means.

It seems like it would be a bit bizzare to disallow only &, wouldn’t it? Also, I expect & and * to be the most common use cases for this…