While useful as a list of handy libraries, I don't think you need to concern yourself with using such a framework if you want to build a CLI app in Rust. If your intended CLI interface isn't extremely simple, then pick a handy argument parser like clap or structopt (which is built on top of clap). From there add these other libraries only if you feel the need.
A project like this can still be very useful if only to show newbies which libraries are the canonical ones. I've noticed with Rust their are many libraries which any experience Rust user would know about but which are not obvious to a newbie.
But it doesn't do that either. For example, it uses failure for error handling, which has been deprecated for quite some time.
It would be better to just go look at real CLI utilities and see what they do instead of trying to use something like this IMO. This project seems to just be throwing everything against the wall. It's likely you won't need most of it. For example, this template uses twice as many dependencies as ripgrep.
I consider rand, clap, tokio, serde, and hyper, among others, to be canonical Rust libraries.
There may be alternatives, but a new person might be wondering "how do I generate a random number in Rust" and not want to roll their own RNG or find another library.
And that's not to say you have to use any of those in any particular project, just that they are the main options for achieving their particular functionality.
This looks nice. We switched from cookiecutter to yeoman and it’s been nice, but a bit annoying to need node, a custom node package, and a pile of node modules to get the same effect. I’ll give this a try today. I think my team would love having a single binary to generate our boilerplate.
Pretty edge case use case over here, but we used cookiecutter (and now yeoman) internally for developing user-configured extensions to our app.
The extensions all have a lot of boilerplate so we use it as a replacement for a PHONY make target for niceties for the extension author like question prompts, enumerated lists for selecting, etc.
Indeed, much of what Failure did well has since been upstreamed into Rust's own std::error::Error type. The modern recommendations for error handling convenience libs are thiserror (for library crates, where you want to define errors) and anyhow (for binary crates, where you just want to consume errors), both of which are from the author of Serde.
Nonetheless starting people off with something deprecated is not a good idea imo, and will only serve to making migration harder in the future because more and more people keep using said deprecated thing.
I was just wondering. I'm new to rust and still getting my bearings. Seems like there's a lot of options for error handling, from doing it yourself with an enum to snafu to thiserror and anyhow or (apparently deprecated) failure
Yep! Really, most of the error handling libraries just reduce the boilerplate associated with creating your own error types. SNAFU also adds some opinions to the mix.
You can see what the libraries do by expanding the procedural macros they use. When you look at the output, it's nothing special that you couldn't have done yourself!
If you haven't seen it, I'll give a shoutout to abscissa[0]. It's used in production by quite a few apps, basically had everything I was looking for, and demonstrated thought towards why dependencies they have chosen and what those dependencies transitively include.
That you need a "framework" to build simple CLI tools does not seem to speak too well of the language. I know nothing about rust, but isn't there a simple facility for using argc, argv, and the like?
You do not "need a framework" to build simple CLI tools in Rust. Most people use a command line argument parser, the most popular being clap [0]. Or you can just use std::env directly.
Or you can use getopts if that's your thing (it's also a library so limited gain over clap/structop, probably smaller & faster to compile though) e.g. that's what Brian Cantrill does[0] because they're an old fogey[1] :D
What clap gives you is something more like Python's argparse, which offers things like convenient parsing, automatically generated manpages and error/usage messages, etc.
> (I'm sure people will shout that this isn't the right way to parse optional flags)
Since that sounds like a challenge, just wanted to make sure that people are aware of Iterator::nth (https://doc.rust-lang.org/std/iter/trait.Iterator.html#metho...), which means you can entirely replace lines 8 and 9 with `let cartridge_path = env::args().nth(1);` :) In combination with Iterator::any to replace line 10, you can avoid a whopping five whole heap allocations this way!! :P
Ooooh thanks for sharing! I am a beginner to Rust (this emulator being my second project). I was not aware of that.
I feel like when I'm done I need to find a bit of cash and get a veteran to code review the whole thing. I'm learning a ton by suffering through it myself. But also probably missing a lot of great shortcuts and tips.
I assume the "five heap allocations" is kinda tongue in cheek? My understanding is that while it is good to avoid heap allocations, given this is a called-once piece of code, it's not really a big deal?
> I assume the "five heap allocations" is kinda tongue in cheek? My understanding is that while it is good to avoid heap allocations, given this is a called-once piece of code, it's not really a big deal?
Indeed. :) I can't envision a circumstance where avoiding exactly five small allocations outside of any loop would be observable in either time or memory usage. As a Rust programmer it simply provides a warm and fuzzy feeling to avoid allocations in places where it not only doesn't obscure the code, but actually makes it shorter. At best, this could be a small step towards running your code on embedded hardware (which isn't unreasonable for an emulator like this), but only if you were to also eliminate all other allocations within your program.
In this case the framework means set of dependencies. If you want to parse short-opts, long-opts etc. you need dependencies in most languages. Python is an exception, because of batteries included approach.
With Rust you will soon see that most applications require some sort of dependency like serde for serialization, etc.
Most languages have terrible CLI parsing support, I have yet to find something built in that matches Python’s argparse module. Hell, even “modern” languages like go suffer from this.
Python’s success is at least partially due to its “batteries included” methodology, but many of its standard modules didn’t get any support because external solutions just turned out to be better. Rust maintains a small but high quality standard library in part to avoid the problems that Python's standard library fell into. Things like cli parsers can be downloaded easily using cargo's amazing tooling. We get packages like structopt for example, which provides a custom derive parsing command line arguments:
IMO structopt is way superior to argparse (which is itself not very good, it works to avoid a dependency but if I already have dependencies I'd rather use click).
26. Show HN: Rust-starter, a boilerplate to build Rust CLI applications (github.com/rust-starter) 18 points by csomar 19 minutes ago | flag | hide | past | 6 comments
27. Finland has slashed homelessness; the rest of Europe is failing (economist.com) 30 points by ashergill 19 minutes ago | flag | hide | past | 11 comments
28. The Reasons I’m Joining BIGtoken as CEO (medium.com/crypto-oracle) 3 points by simonebrunozzi 19 minutes ago | flag | hide | past | 1 comment
29. Upvote to encourage more people to visit New Links on Hacker News (ycombinator.com) 164 points by crazypython 21 minutes ago | hide | past | 19 comments