In numerical processing code like you write in Matlab, Python Numpy, Julia and so on, you often slice arrays, both 1D, 2D and more:
https://docs.scipy.org/doc/numpy-dev/user/quickstart.html
In such code you sometimes have complex expressions that contain several slicing operations, so to keep that code readable you really want a compact and noise-free slicing syntax.
Rust offers a readable array slicing syntax, but there’s something I’m missing in Rust, that I’d like Rust to steal from D. But first I show some examples with Python code (Python REPL):
>>> s = "abcdefgh"
>>> s[2:]
'cdefgh'
>>> s[2:-1]
'cdefg'
>>> s[2:-2]
'cdef'
>>> s[-2:]
'gh'
>>> s[-4:-2]
'ef'
In Python the index -1 refers to the last item, -2 is the penultimate, and so on. This is handy because you often enough want to slice taking the end of the array as reference point.
But handling negative numbers like that slows down all the array access, and I don’t like when sometimes, because of a bug I create a negative index and my Python code still keeps running, and giving wrong results instead of raising an out of bounds exception.
The D language has solved the problem efficiently, more safely, and in a sufficiently compact way using the “$” operator. This is D code equivalent to the Python code above:
void main() {
import std.stdio;
auto s = "abcdefgh";
s[2 .. $].writeln;
s[2 .. $ - 1].writeln;
s[2 .. $ - 2].writeln;
s[$ - 2 .. $].writeln;
s[$ - 4 .. $ - 2].writeln;
}
The outputs is the same (D strings/dstrings/wstrings can be sliced):
cdefgh
cdefg
cdef
gh
ef
“$
” means the length of the array, but you can’t use it like “a.$
”. So the D code:
a[$ - 2]
b[$ - c[$ - 2]]
d[random(0, $)]
Is equivalent to the Rust code:
a[a.len() - 2]
b[b.len() - c[c.len()- 2]]
d[random(0, d.len())]
As you see in the $
refers to the length of the innermost array.
So $ makes the code shorter, but also safer because it’s more DRY, you don’t have to state the name of the array twice.
So I’d like the “$” operator in Rust slices/arrays/vectors too.
In D you can also overload the “$” in library code if you define the “opDollar” method in struct/class, so you can use a nice slicing syntax in library-defined matrices too, for numerical processing:
mat[$-1, 0]
int i = r[$-1, 0]; // same as: r.opIndex(r.opDollar!0, 0),
// which is r.opIndex(r.width-1, 0)
int j = r[0, $-1]; // same as: r.opIndex(0, r.opDollar!1)
// which is r.opIndex(0, r.height-1)
More info about opDollar
usage:
https://dlang.org/spec/operatoroverloading.html
opDollar
is used in the ndslice
in the standard library:
https://dlang.org/phobos/std_experimental_ndslice.html
https://dlang.org/phobos/std_experimental_ndslice_slice.html#.sliced
You can use it like:
t[3..$,0..3,0..$-1]
That is similar to the more compact NumPy syntax:
t[3:,:3,:-1]