Live data from Hacker News

Rust CLI with Clap

tucson-josh.com

61–70 of 92 posts

Re: Rust CLI with Clap

#61
post #56
post #51

Earlier quoted context omitted.

> Why wouldn't you default to the most full-featured option when its performance and space usage is adequate for the overwhelming majority of cases? This is the logic of buying a Ford F-150 to drive your kids to school and to commute to the office because you might someday need to maybe haul some wood from the home improvement store once. The compact sedan is the obviously practical choice, but it can’t haul the wood…

Well you hit the nail on the proverbial head. The compact will handle 99% of people's use-cases, the truck will handle 100%. People don't want the hassle of renting something or paying for help for the 1% of cases their compact wouldn't handle. Believe it or not, I'm with you; I live somewhere where it's sunny all year round, so I get around with a motorcycle as my primary transportation year-round and evangelize the…

Not sure why you’re being downvoted. I also don’t like oversized motor vehicles but I think the parable is sound;

If the effort of switching out when you need the last 1% is higher than whatever premium you will pay (compilation time/fuel cost) - especially as a small ongoing cost, people will likely choose it.

I’m not saying this as if its wisdom into the future, only in that we can observe it today with at least a handful of examples.

Re: Rust CLI with Clap

#62

I like clap a lot, however I find that clap derive is not very easily discoverable. I always have to google for the right macro incantation to get what I want. Whereas editor completions from rust analyzer get me quite far without needing to leave my editor when I'm just using an ordinary library. I think this is more a criticism of rust-analyzer than clap itself, any macro-heavy library I have similar issues with. (…

FYI, maybe for you and other readers. My key to really understanding clap's derive macro was to understand that the macros takes as argument every methods of clap's Command struct https://docs.rs/clap/latest/clap/struct.Command.html

Looking at this resolved most of my issues about discoverability.

Re: Rust CLI with Clap

#63
post #33

In my opinion, clap is a textbook example of over-engineering for a single metric (UX) at the expense of all other considerations (compilation speed, runtime cost, binary size, auditability, and maintainability). It is an 18kloc command-line parser with an additional 125kloc of dependencies that takes nearly 6 seconds to compile (‘only’ 400ms for an incremental build) and which adds nearly 690KiB to an optimised rele…

I can understand this, if we were talking about JavaScript CLIs that requires GBs of dependencies. But 690KiB for modern computing is a drop in the ocean. It is not something you should base or make a consideration of unless you were doing embedded programming.

690KiB is a far compromise if Clap provided, for example, better performance or better code readability and organization. The benchmarks you provided shows the performance is practically the same which is close to no library usage.

I did do a bit of CLI work (I try to maintain https://github.com/rust-starter/rust-starter) and will always pick up clap. It just happens that even for the simplest CLIs out there, things can get hairy really fast. A good type interface that let me define my args as types and have extras on the fly (ie: Shell completion code) is worth the less than 1MiB overhead.

Re: Rust CLI with Clap

#64

Earlier quoted context omitted.

That 690KB savings is 1/97000th of the RAM on the machine I develop and run most of my Rust software on. If I ever encounter a single howto or blog post or Stack Overflow answer that tells me how to use Clap to do something 5 minutes more quickly than with an alternative, it’s paid for itself. Amdahl’s Law says you can’t optimize a system by tweaking a single component and get more than that component’s total usage b…

At this point you're just flexing that you have 96GiB machine. (Average developer machines are more like 16GiB) But that's not the point. If every dependency follows same philosophy, costs (compiler time, binary size, dependency supply chain) will add up very quickly. Not to mention, in big organizations, you have to track each 3rd party and transitive dependency you add to the codebase (for very good reasons).

96? It sounds more like 64 to me, which is probably above average but not exactly crazy. I've had 64 GB in my personal desktop for years, and most laptops I've used in the past 5 years or so for work have had 32 GB. If it takes up 1/4700 of memory, I don't think it changes things much. Plus, argument parsing tends to be done right at the beginning of the program and completely unused again by the time anything else happens, so even if the parsing itself is inefficient, it seems like maybe the least worrisome place I could imagine to optimize for developer efficiency over performance.

Re: Rust CLI with Clap

#65
post #45

Earlier quoted context omitted.

> Why would you default to the biggest, slowest option? Because it's not very big, nor very slow. Why wouldn't you default to the most full-featured option when its performance and space usage is adequate for the overwhelming majority of cases?

These decisions accumulate then all of a sudden you have a project that takes ten minutes to build for almost no benefit.

Maybe. If your build is too slow, fix it. But pre-emptively microoptimising your build time is as bad as pre-emptively microoptimising anything else. Set a build time budget and don't worry about it unless and until you see a risk of exceeding that budget.

Re: Rust CLI with Clap

#66
post #7

It really bothers me how much people use crates in Rust. "Minimalist" crates have tens of dependencies. It's like the node.js of systems languages. Touching it feels gross.

… I don't want every program to attempt to implement argument parsing; bespoke implementations will be lower quality than clap. Not reinventing an argument parser is an extremely reasonably dependency to take. Clap, on the non-derive side, has approximately two dependencies: anstream/anstyle (for terminal coloring, another thing that sounds deceptively simple at first pass, if you think all the world is a VT100, but…

  On the derive side, there's the usual proc-macro2/quote/syn trio, but
  those come up frequently in derive crates due to what they do, and other
  than that, there's just `heck`, which is again an obvious dependency in
  context.
They're common dependencies, sure, but not necessarily the same versions. So, yeah, it's entirely possible you'll end up building multiple versions of quote/syn.

Re: Rust CLI with Clap

#68
post #33

In my opinion, clap is a textbook example of over-engineering for a single metric (UX) at the expense of all other considerations (compilation speed, runtime cost, binary size, auditability, and maintainability). It is an 18kloc command-line parser with an additional 125kloc of dependencies that takes nearly 6 seconds to compile (‘only’ 400ms for an incremental build) and which adds nearly 690KiB to an optimised rele…

Clap has also great dev ux, so I wouldn't put maintainability as an expense.

Re: Rust CLI with Clap

#69
post #47
post #39

Earlier quoted context omitted.

Hmm isn't optimizing to save 690KiB for an optimised release binary and getting incremental builds to be significantly less than 400ms actually much closer to the after-mentioned "every web site must be able to scale like Facebook” type logic" ?

No, it is the following the principle of YAGNI.

The “every website must scale like Facebook” mindset is premature optimization driven by hypothetical future needs exactly what YAGNI advises against. But in your case, you’re investing time upfront to avoid a heavier dependency that already works and has no clear downside for the majority of users.

If you don’t actually need ultra-small binaries or sub-200ms compile times, then replacing Clap just in case seems like a textbook case of violating YAGNI rather than applying it.

Re: Rust CLI with Clap

#70
post #33

In my opinion, clap is a textbook example of over-engineering for a single metric (UX) at the expense of all other considerations (compilation speed, runtime cost, binary size, auditability, and maintainability). It is an 18kloc command-line parser with an additional 125kloc of dependencies that takes nearly 6 seconds to compile (‘only’ 400ms for an incremental build) and which adds nearly 690KiB to an optimised rele…

You’re right that there are only trade-offs in engineering. But the key to evaluating trade-offs is evaluating impact, and how long my dependencies take to compile when I first check out a repo or whether it takes 1ms or 2ms to parse my command line (if we’re even talking about something above microseconds) have no discernible impact for approximately all use-cases. If you’re making some odd CLI tool that has to run…

> Otherwise you’ve abjectly failed to evaluate one of the most important trade-offs in engineering: whether something is even worth your time to think about.

Phew, several folks have replied to me about how it’s not worth the time thinking about these impacts at all, thus creating a paradox whereby more time has been spent thinking about writing about whether to think about it than has been spent in not thinking about it and just accepting that I wrote a reply on HN about how I feel there are more suitable command-line parsers than clap for most Rust projects! :-)

I agree that much of high-level engineering is knowing whether something is worth thinking about; in this case, I did the thinking already, and I am sharing what I know so others can benefit from (or ignore) my thinking and not have to do so much of their own. If my own personal anecdote of significantly reducing compile times (and binary sizes) by taking a few minutes to replace clap is insufficient, and if the aggregate of other problems I identified don’t matter to others, that’s alright. If reading my comment doesn’t make someone go “huh, I didn’t know {argh|gumdrop|pico-args} existed, clap does seem a little excessive now that you mention it, I will try one of these instead on my next project and see how it goes”, then I suppose they were not the target audience.

I don’t really want to keep engaging on this—as almost everyone (including me) seems to agree, command-line parser minutiae just aren’t that important—but I guess I will just conclude by saying that I believe that anchoring effects have led many programmers to consider any dependency smaller than, say, Electron to be not a big deal (and many think Electron’s fine too, obviously), whereas my experience has been that the difference between good and bad products usually hinges on many such ‘insignificant’ choices combining in aggregate.

Assuming whichever command-line parser one uses operates above a certain baseline—and I believe all of the argparse libraries in that benchmark do—it seems particularly silly to make wasteful choices here because this is such a small part of an application. Choosing wastefulness because it’s technically possible, then rationalising the waste by claiming it increases velocity/usability/scalability/whatever without actually verifying that claim because it’s ‘not worth thinking about’, seems more problematic to me than any spectre of premature or ‘unnecessary’ optimisation. I hope to find better ways to communicate this in future.

Post reply on HN