Rust 2019: Tame Complexity through Community Involvement Tools
internals.rust-lang.org
internals.rust-lang.org
- `Error Handling` is a bit of a dumpster fire right now. Rust has something called a `Result` enum which is similar to `Either[Error,T]` monad in Scala however every single Rust crate I have used so far its creating its own `Error` enum which makes it really hard to compose `Result`. Ideally I would like to chain `Results` as `e1.and_then(e2).and_then(e3)` but its not possible due to incompatible error enums. Ended up using `https://docs.rs/crate/custom_error/1.3.0` to align the types.
- A lot of basic things are still influx and community wide standards have not been established. For example: I needed to externalize some environment specific settings in a Config but couldnt figure out where to put non-code assets in a cargo project and then how to reliable read them. In JVM world `src/main/resources` acts like a standard place for stuff like this but that patterns has not been established yet.
- Distributing code inside the company is hard because there is no integration with Artifactory or similar tools. We are directly referring git sha in Cargo right now and waiting for better solutions.
- Rust comes with a default unit test framework but it pretty bare bones. I havent seen examples of test fixture, setup/teardown support and loading test configs etc.
- I really like Rust compiler because of really good error messages it produces but its really slow and you start to notice it as you add more code/external crates
-IDE support is good but not great. I am using IntelliJ with Rust plugin as we use IntelliJ for Scala/JVM and it is nowhere as good as even Scala plugin which is pretty mediocre in itself.
Overall I am pretty happy with the language (except for Error issue) and most of my gripes are around the ecosystem and tooling around the language. Hopefully these will be resolved as language gains more momentum
This is one of the things that I really love about Rust - it has a testing framework that is so simple that it subtly pushes you to write better tests and better code.
What I mean by that is - it really wants you to write simple tests with no mocking and no convoluted state using simple asserts, and it really wants you to write code which is trivially testable. In other languages this might be problematic, but in Rust this synergises really well with other language features such as #[derive(...)], sum types and pattern matching. If you write good, idiomatic Rust code then all of those extra features of other testing frameworks are usually totally unnecessary.
For integration tests, both the Rust compiler as well as the Servo web engine have written their own test runners with an accompanying set of tools. This allows the test format to be as flexible as the target domain of the program. In fact, servo can just simply use the cross-browser wpt [1] test suite.
As for avoiding to initialize heavy objects, I only know about the Rust compiler's test runner initializing the entire compiler every time from zero for every single test file. The result is a quite long testing-time. Suggestions by me to use a shared driver were rejected by them because one test might affect the other one.
But in theory you could write your own custom test runner that has as much shared state as possible. You might also want to check out cucumber-rust [2] which I think allows for some way of sharing. You could also just group smaller tests into a small set of bigger tests where each group of tests shares some resource.
[1]: https://github.com/web-platform-tests/wpt [2]: https://github.com/bbqsrc/cucumber-rust
That would be an ideal combination for me: do performance critical stuff in Rust, use Scala everywhere else.
foo().map_err(|e| MyError::FooError(e))?
.bar().map_err(|e| MyError::BarError(e))?; foo().map_err(MyError::FooError)?
.bar().map_err(MyError::BarError)?;Is there a reason why `map_err()` doesn't achieve what you need - i.e. to get everything into your error type no matter where it came from?
For example: OtherLibResult.map_err(|e| MyError::from(e))
Unless I'm mistaken - you ultimately are doing something like this in one form or another, because if you never match on the different Error variants that happened somewhere along the pipeline- then those details are being swallowed.
Implementing a From trait at least forces you to make that choice (all in one place too)- and then you can keep composing the results as needed since it's all in your MyError type
If you make your functions return `Box<dyn Error>` (or `failure::Error`), they will all convert out of the box. The `?` operator performs conversion itself. For chains `.map_err(From::from)` does it.
There is an eRFC for better integration of custom test frameworks.
If you don't know the idioms you end up doing a sort of transliteration of the source language where the concepts may work against the nature of Rust. A developer can spend a long time barking up the wrong tree with few indicators as to which is the right tree.
As an example of what I mean. Here is a program that I wrote in JavaScript specifically because I could not find a way to write it in Rust that felt like I was doing it the right way.
https://codepen.io/Lerc/pen/yQxmob?editors=0010
I could come up with Rust versions that were basically emulating pointers with array indexes(and a mess when something is deleted), or map versions that incurred lots of run-time lookup. The crux of the problem, I think is either how to do a mutable graph of mutable nodes, or how to do map on a immutable graph of immutable nodes to a new immutable graph of immutable nodes in the next state along.
I'm sure others have this issue of "I know how to do it in X, doing it that way in Rust is a mess, what's the right way?"
I think this idea is pretty good!
should be much less work than creating yet another repository.
i think there was at least one language that made rosettacode their official repository for code examples. so all their solutions were vetted by experienced developers.
i believe the rosettacode maintainers would allow adding a note to each example that has been checked. (simply add it to the description of the solution, so that people know which examples are recommended)
There is so much genuine compassion, diligence, and attention in the community, and it shows everywhere.
Other language communities, take note.
A bit of really nit-picky grammatical feedback: you use it’s vs its wrong multiple times in the article. It was surprising given your solid command of technical prose displayed in the post. Try to bone up on the correct usage of the two. It makes a big difference. Thank you!!
Edit: Fixed! Thanks again.
ReasonML is a reskin (of ocaml), Nim is not
^^ This link is a pre rfc for adding good support for those types of things.
It's a huge language.
I haven’t looked into which micros are supported by Rust in actuality because I checked their main site and saw an old Nordic, a few old STMs, an old NXP, and some old MSPs, then left the page.
If I was a hobbiest this might be ok and I might research it more. As a professional, I pretty much noped out of there assuming that it’s just nowhere near ready for me.
I’d like to see it work! But until there is an IDE with debugging using code overlay and breakpoints... Rust is just not for me. I wonder what year they get there?
Edit: apparently there is a gap between what hobbiests consider acceptable and what my company would need that the Rust fans can’t imagine - this somehow means my opinion isn’t valid. Let me know when Keil or IAR or anyone sells a supported and professional IDE with a Rust compiler.