Agreed. I find Rust pushes code to be beautiful at the large design level, but has some ugly warts at the shallow syntax level. If a tradeoff has to be made it's the right one, but I think in some cases it's an unnecessary tradeoff, and the syntax quirks could be fixed.
Copy/Clone
There are a few relevant cases for copying means:
-
Types that are just a bitwise copy, e.g. i32
.
-
Types that are logically trivial to copy, but just slightly more expensive than a simple bitwise copy. E.g. String
or Arc<T>
where T
doesn't have interior mutability.
-
Types that are logically trivial to copy, but significantly more expensive than a simple bitwise copy. E.g. Vector<T>
or Matrix
.
-
Types for which a copy is semantically important, like FileHandle
or Arc<Cell<T>>
.
C++ spells all of these as... nothing. Rust spells #1 as nothing, #2-4 as .clone()
.
That's an improvement over C++, but .clone()
is just a very noisy way to indicate such a common operation, and conflating #4 with the other cases reduces the value with a bunch of false alarms. I'd rather be able to either indicate semantically trivial copies, so e.g. Arc<T>
could be silent, or at least make .clone()
less noisy.
Arrays
The Python numerics ecosystem (numpy, scipy, pytorch, numba, taichi, etc.) is a great example of how a flexible array syntax can enable all sorts of great things.
Rust's array syntax is limited in a couple of ways:
-
Single argument, so multi-dim arrays must use a[(i,j)]
. This is minor, just one of those little papercuts that makes multi-dim array stuff annoying.
-
index()
and index_mut()
return references. So array-like objects that return a computed value must actually have it stashed away somewhere. That means e.g. you can't do something like have matrix[(0..3, 0..3)]
return a submatrix. The only real workaround is to just not use array syntax, and instead use matrix.idx(0..3, 0..3)
or similar. Not the end of the world, but ugly.
#1 would be relatively simple to fix, by auto-tupling multiple args. I.e. make a[i,j]
mean the exact same thing as a[(i,j)]
. Fortunately this is currently a syntax error, so such a change would be backwards compatible.
#2 could be fixed with a new Index
trait, that returns by-value. It's even possible to do this backwards compatibly, with a blanket impl to convert between the two variations. (Some Deref
shenanigans are needed to work around the current syntax sugar definition of a[i]
as *a.index(i)
, but it's doable.)