I've wondered why Rust doesn't allow let x = +3
? Many other languages do, Python, C#, C++ and more. I can see how it's redundant, but one could also say it is inconsistent as let x = -3
works. Then again let x = - 3
kind of works but let x = + 3
would only work if we make + a unary op, which falls into much of the same argument. Has this been discussed somewhere before?
Previously:
I'd be in favor of this just working for literals, but do understand how it might suggest unary plus as an operator (thus why I didn't just suggest making it work).
By the way, this is technically a breaking change so would need an edition boundary.
As long as we have reasonable diagnostics for this, with rustfix suggestions, I don't think we need to support such literals. They certainly don't seem worth the trouble of a breaking change across an edition boundary.
Out of curiosity, would you add them if you had a time machine?
While the reasoning is fairly weak, leading positive signs are useful for e.g. matrix literals with mixed sign numbers:
matrix! {
-1.0, +0.0, +0.0;
+0.0, -1.0, +0.0;
+0.0, +0.0, -1.0;
}
Given any such setup basically requires #[rustfmt::skip]
to benefit from the visual alignment (by same number of significant figures, not via space alignment, may I add), you can argue to just replace the plus with a space. But the effect is ime wrong, drawing attention to the negatives improperly:
matrix! {
-1.0, 0.0, 0.0;
0.0, -1.0, 0.0;
0.0, 0.0, -1.0;
}
Basically the only reason to use unary plus on literals is for consistency with other literals of mixed sign.
(And maybe this isn't the best example, since I could use -0
if I wanted to make my float hardware mad )
The same thing actually happens with variables, too, e.g.
matrix! {
+cos, +sin;
-sin; +cos;
}
but I don't really think that justifies unary plus as an operator, so...
(Fun completely off topic addition: the "coerce to boolean" operator in many loosely/dynamically typed languages is fairly well known as !!x
. But similarly for "coerce to number", you can use +x
(or sometimes - -x
, but not --x
).)
Interestingly, -1
is actually already a literal
sometimes, not just an operator-then-literal.
The rotation matrix is definitely the place where I've wanted +
in the past. But of course there are other problems with formatting that -- rustfmt
wants it on one line or four lines, both of which are bad.
At the risk of straying off-topic, putting comments at the end of lines can help with that:
let matrix = [
1.0, 0.0, //
0.0, 1.0, //
];
Only in very particular cases.
let matrix = [
1.08, 0.0, //
0.0004, 1.0, //
];
It is an ongoing disappointment to me that most automatic code formatters don't believe in column alignment. The only exception I know of is perltidy.
Regardless, I do think it would be nice to allow an explicit leading + on numeric literals, although I would not call it a high priority (are we still waiting for hexadecimal floating point literals?)
This was a deliberate decision that the style team made when determining the standard Rust style. The tradeoff there is that alignment can sometimes (not always) produce more appealing code, but alignment also causes changes to ripple outwards from the point of a change, making for larger and noisier diffs. There's no objectively better option there, just a tradeoff, and we ended up making the tradeoff in the direction of long-term maintenance and diff reviewability. That's probably the style team's third most controversial design decision, after spaces and indent width.
That said, I would love to see a mechanism to label specific bits of code with #[rustfmt::align]
(as well as other variants like #[rustfmt::grid]
or similar), for code where alignment makes a substantial difference and changes rippling outwards in diffs isn't as big of a deal.
The block alignment principle: https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/principles.md#overarching-guidelines
The other things that I recall coming up in the decision to prefer block is that it's more friendly to screen readers, as column alignment is quite awkward to do without a visual queue.
90% of what I want column alignment for is tables of one variety or another, so that would be plenty good enough, I think.
Do you mean that we have something like
matrix! {
-1.1234, 0.0, 0.22;
0.0, -1.0, 0.0;
0.0, 0.01244, -1.0;
}
Then add something like
matrix! {
#[rustfmt::grid]
-1.1234, 0.0, 0.22;
0.0, -1.0, 0.0;
0.0, 0.01244, -1.0;
}
Next run rustfmt
and it becomes:
matrix! {
#[rustfmt::grid]
-1.1234, 0.0, 0.22;
0.0, -1.0, 0.0;
0.0, 0.01244, -1.0;
}
?
Something like that, but it would also work for:
#[rustfmt::grid]
let x = [
1, 2, 3,
4, 5, 6,
7, 8, 9,
];
In this case the two lines are preserved, so the formatting is good.
The columns are not preserved, but Rust formatting rules avoid keeping vertical alignments, because it would cause more line changed than the minimum required.
I really like this idea, but I have some questions:
-
If the grid's size increases and becomes wider than 100 characters (the maximum line width by default), what should rustfmt do? Should it align the columns anyway, should it wrap the elements somehow, or bail and return an error?
-
How are the items to be aligned? Integers are usually right-aligned. Floats could be aligned at the decimal point, other tokens should be left-aligned. But what should rustfmt do when a column contains both numbers and other tokens? Should each cell be aligned individually, like in Excel? For example
#[rustfmt::grid] frobnicate! { 1, 127.5, 3.14159, foo, bar, 2, hello, world, 13, 3, 5, 8, }
That definitely needs defining. I had originally envisioned grid
exclusively as "please don't re-wrap these lines, preserve where I put line breaks"; I wasn't thinking about alignment at all. So, for instance:
#[rustfmt::grid]
let x = [
1, 2, 3,
10, 20, 30,
100, 200, 300,
];
That isn't necessarily the behavior everyone would expect, though.
Implementing an alignment system would require far more specification.
In general, I'd be in favor of someone writing an RFC proposing a precise definition and mechanism for rustfmt::
attributes like these. And they do need precise definition.
I would expect that behavior from something called #[rustfmt::skip]
.
I would still want rustfmt to otherwise format the code, I just want it to not change the linebreaks within (for instance) lists of comma-separated things. It should, for instance, still indent the overall code, and make sure there's a trailing comma, and ensure there are spaces between things in the list and no space between a thing and the subsequent comma...