Amazing stuff, honestly felt like black magic at the time.
Thanks for your work on this
while it is pretty cool, it's also a bit awkward thinking about machine structures and machine types in high level python. there are some gotchas with respect to the automatic type inference.
- Yes you get const generics, but no you do not get const generic expressions
- Yes you can provide impls for traits, but no you cannot impl a foreign trait for a foreign type
- Macros cover these gaps in meta-programming, but macro code is really painful to read/write
- If you want to write one tiny little proc macro, you need a whole. new. crate. So I usually write ugly, convoluted "declarative" macros instead of what would properly be a proc macro
- Last time I wrote a Rust macro that generated a lot of code, the intellisense in VS Code stopped giving hints for functions in the macro output. Breaking intellisense is very painful
- Yes const fns exist, but no you cannot use iterators or for loops in them. AFAICT a lot of library authors just don't go through the trouble of defining const fns. I was bit by this when I tried to make a const array using the ndarray library. Instead you have to go through the whole song and dance with OnceCell.
- Speaking of which, OnceCell feels like a downgrade compared with static initialization in C++. You get more soundness, but also much more verbosity
There are very good reasons for many of these restrictions, but still. I fear doing anything too fancy because I've come to expect that the language will yank away the football at the last second.
PS. Not a language shortcoming, but - do not just write out idiomatic vector math expressions as you might do with Eigen like:
``` let a = b + c + d + e; ```
IIRC Eigen can be smart enough to only allocate one result vector for this expression. Rust numeric libraries, on the other hand, will allocate many unnecessary temporaries. You need to be thinking much more imperatively to get similar performance:
``` let mut a = b + c; a += d; a += e; ```
Also, if you want a Python interface for your library, PyO3 allows you to call Rust from Python naturally. It definitely needs better documentation, but otherwise its quite good.
> for most "normal" uses, you'd probably be fine with having your code written in numpy or pandas
In my experience this is the case. Occasionally though, there might be an bottleneck, and Numba can be a good way to handle it. E.g. when implementing seam carving, I found normal Python / NumPy too slow, and same with Naive Bayes, so used Numba. (Why was I implementing these, instead of using a library? As an exercise. But I guess the takeaway is that if you want to do something more intensive, and are implementing it yourself rather than using a library, Numba can be a good option).
You can try twisting numpy/pandas into a solution, but it might be much simpler to just write a dumb numba function which will be easier to maintain since the logic will be very clear.
> One hypothesis is instruction-level parallelism
This is Python code, whose execution has a massive gap to the actual CPU instructions executed. The experiment result feels more like something related to the memory cache.