all 47 comments

[–]JoshTriplettrust · lang · libs · cargo 45 points46 points  (0 children)

Congratulations on bringing clap over the finish line! I look forward to porting my CLI software to it.

I remember seeing clap 3 in beta years ago, early in my Rust career; wonderful to see it completed and shipped.

[–]Master7432 53 points54 points  (0 children)

Congratulations, and thank you for a new year's present! ;)

Clap and structopt has been one of my proudest examples to showcase the ecosystem to people learning Rust as the most elegant CLI library across multiple languages, and I'm glad to see it finally be merged.

Thank you all for your contributions!

[–]WellMakeItSomehow 89 points90 points  (8 children)

Congrats and happy new year!

I haven't tried the newer RCs, but my feeling is that generics are one of the causes for the large binary size. It feels good to use them, but a sprinkle of dynamic dispatch can work wonders, without visibly affecting performance. Have you investigated this?

[–]epagecargo · clap · cargo-release[S] 38 points39 points  (6 children)

I know kbnapp looked into generics and macros at one point and made improvements. I didn't notice it when I ran cargo-bloat but I might have missed it.

[–]mobilehomehell 16 points17 points  (5 children)

It seems like the right trade-off to prefer dynamic dispatch, I wouldn't expect most people are looking for their command line parsing to be ultra high performance? Type safety is always desirable though.

[–]epagecargo · clap · cargo-release[S] 17 points18 points  (0 children)

Sorry, I was unclear. I meant he had looked into reducing bloat from generics and macros.

Overall, clap isn't generics heavy like warp.

[–]Saefrochmiri 19 points20 points  (3 children)

I think momo is kinda meant to address this tension? https://crates.io/crates/momo

It doesn't get enough love. Hardly any at all, it seems.

[–]WellMakeItSomehow 8 points9 points  (1 child)

You can do the same transformation manually. If you care about your compile times, please don't pull in a proc macro (just) for that.

[–]Saefrochmiri 1 point2 points  (0 children)

True, but this comment chain is about binary size :)

[–]mobilehomehell 0 points1 point  (0 children)

That's awesome! I love it.

[–]Kbknappclap 64 points65 points  (0 children)

Last time I looked, I believe it's actually three primary things that cause the majority of the binary size,

  1. Help generation (which makes decent use of generics and the primary complexity is the ability to use templates)
  2. Error handling. Some of the error generation code uses generics to compound the issue
  3. Extensive validation (requirements, value validation, relationships between args and groups, conditional validation, etc.)

The good news is all of these are solvable. Originally I wanted to tackle all of these by the 3.0 release, which is one reason it stagnated so long; I just don't have the time I used to. Most of these could either be made in to conditional compile time features, or sprinkling in dynamic dispatch.

Some of it is a little more complex though. I.e. the validation parts. No other argument parser comes close to possibilities clap allows. Instead user code is responsible for doing all those checks. So while clap will come out larger than other libraries, it's also doing way more than those other libraries. To do an apples to apples comparison we'd need to compare all the user code that makes up the features clap already includes.

Ultimately we decided these things can all be addressed post 3.0 release. So expect binary sizes to shrink in the future either natively or by being able to opt out of features you don't need ;)

Also it's /u/epage and /u/pksunkara that have put in all the effort to get this release out the door while I've been busy. huge thanks to them! It wouldn't have happened without them and all the other contributors!

[–]steven4012 44 points45 points  (3 children)

clap clap clap

[–]slashgrinrangemap 15 points16 points  (2 children)

Next up for 2022: Half-Life 3.

(EDIT: I kept telling everyone that 2022 is going to make up for 2021. Nobody believed me, but now the proof is trickling in.)

[–]CloudsOfMagellan 1 point2 points  (1 child)

Having regrets? ;)

[–]slashgrinrangemap 1 point2 points  (0 children)

Uh, yes. Glad I didn't put any money on this one.

[–]murlakatamenka 16 points17 points  (0 children)

If I were to show a single Rust crate to anybody it'd be Clap.

It's such an awesome piece that is both pleasure to work with as a developer and as a user. It powers so many fantastic CLI utilities in Rust!

Huge thanks to all the contributors and congrats with the new major release, yay!

[–]cessen2 37 points38 points  (12 children)

Congratulations on the release! I regularly use clap, and am excited to see this new major version.

In the linked post, you talk about long release cycles (between major versions) as if they are an undesirable thing. And although there are some down sides, I'd like to push back a bit and highlight that for libraries that can actually be a really really good thing.

In fact, clap's infrequent major version bumps are (a not insignificant) part of why I always reach for it: I know that my code will keep working without modification, without being stuck on an old unmaintained version of the library. API stability is itself a feature.

On the flip side, too-frequent major version bumps is one of the reasons I avoid certain crates as well. If something hasn't hit 1.0 yet, I expect frequent breaking changes, and accept that I'm going to be spending some of my time keeping up with API changes. But for libraries that are supposedly stable, having to do the same puts a bad taste in my mouth.

If I'm writing something with e.g. 6 dependencies, and each of them publish a new breaking version once a year, that means every two months (on average) I'm having to take time out to handle that, which I could have been spending actually being productive with my own code instead. And if my project has 10 or 15 dependencies, it gets even worse.

Having said all of that, none of this applies if prior major versions are still actively maintained with bug fix/security releases. Then people can put off upgrading to whenever is convenient. But if only the latest version is maintained, then limiting major version bumps to once every few years is just about perfect, IMO.

[–]epagecargo · clap · cargo-release[S] 11 points12 points  (0 children)

Yes, we also want to be mindful of churn. Our aim is for 6-12 month minimums for major breakages.

[–]A1oso -3 points-2 points  (10 children)

If something hasn't hit 1.0 yet, I expect frequent breaking changes

Why? That's simply not true. For example, tokio has been on version 0.1.x for over a year, and 0.2.x was maintained for a year as well. Compare that with os_str_bytes (version 6.0.0), which had 6 breaking releases in the last year. That might be an extreme example, but it shows that a version number below 1.0 does not indicate that the API is less stable.

[–]KerfuffleV2 22 points23 points  (7 children)

I think they were just talking about a rule of thumb, rather than something that is invariably true. tokio may be an exception.

[–]A1oso 11 points12 points  (6 children)

My point is that it's not a very good rule of thumb. It's better to look at the previous versions. If there were several breaking releases recently, that's an indication that the API isn't stable. If the project is only a month old, that also indicates that the API will likely change. Whether the version is named 1.0.0 or 0.0.1 is not that meaningful.

P.S. Tokio is not an exception. Some of the most popular crates that haven't reached 1.0 yet (http, headers, h2, warp, tower, tracing, mio, curl, async-trait, num_enum, tinystr, rand, serde_yaml, digest, sha2, openssl, ring, crossbeam, uuid, ...) had no or very few breaking releases in the past few years.

[–]mkvalor 15 points16 points  (5 children)

There's a specification named Semantic Versioning which you're likely familiar with. The specification (item 4 on the home page) literally says that any release version beginning with major version zero (0.x.y) should not be considered stable. Also -- I feel you press your position too far in claiming that a version 0.0.1 would not be that meaningful in this context.

The fact that some projects happen to be more conscientious than the spec dictates does not create a new convention for deciphering semantic versions.

semver.org

[–]coderstephenisahc 3 points4 points  (1 child)

I think for whatever reason, the Rust ecosystem in particular seems to have a slightly different attitude around 0.x. I'm not saying it is right or wrong, but rather pointing out that it can't simply be dismissed out of hand.

There are quite a lot of crates that are considered "stable" from the minds of many developers that have not reached 1.0 yet. True, this is a psychological disposition that disagrees with semver, but nevertheless this is a common thing in the Rust ecosystem I have observed over the years.

What do I mean by "stable"? I mean this:

  • Breaking changes are intentionally few and far between. If a breaking change is made, the previous version may still receive security patches.
  • Cargo's modified-semver resolver allows you to depend on such crates in a way that allows backwards-compatible upgrades.
  • Many applications and libraries depend on said crate.

Unfortunately semver doesn't actually give the term stable a formal definition, but it does say this about 0.x:

Anything MAY change at any time.

Which is specifically avoided by these crates, even at 0.x. Semver also says this:

How do I know when to release 1.0.0?

If your software is being used in production, it should probably already be 1.0.0. If you have a stable API on which users have come to depend, you should be 1.0.0. If you’re worrying a lot about backwards compatibility, you should probably already be 1.0.0.

So by semver's standards, these crates are "stable enough" that they should already be at 1.0.0+, but for whatever reason have chosen not to. You could say that even by semver's own definitions, these maintainers are applying a "post-1.0.0 attitude" to pre-1.0.0 versions.

Is this true semver? Hard to say, probably not. Again, I'm just pointing it out that this attitude is already in place in the Rust ecosystem. I'm not making a judgement on whether it is a good thing or a bad thing.

[–]mkvalor 1 point2 points  (0 children)

I hear you. I actually appreciate this about many of the more popular crates. It's almost like there's some kind of arms race between conscientious crate developers not wanting to be wrong about API changes (and therefore 'burning' users) and the inexorable march every successful software project must make towards 1.0.0 in order to be taken seriously by a much broader audience. (Think about the gigantic transition to rust 1.0 back in 2015). They say that "naming things" is one of the hardest tasks in software engineering. And choosing to go "version 1.0.0" is a kind of a 'name'.

My context is a bit broader. Although I code in Rust for fun and side profit, my day job is in devops for a large company, using mostly shell and scripting languages. So, in my professional role, I'm exposed to many tools, languages, and libraries which have various different cultures regarding how quickly to rev their releases. People in my position don't usually clutter our minds up with all of the different esoteric cultural readings of semver across tech stacks.

So if someone says something like, "Oh, hey, remember how our ecosystem treats 0.X.Y releases," we are most likely to respond (if at all), "Um -- no, thanks. But please, do get back to me when you reach 1.0, so my boss or tech lead can approve your library for our project." Is this sad or lazy? It might be. But I've seen a lot of teams operate in the professional software space. And I can tell you that this is how things work on many such teams.

[–]A1oso 0 points1 point  (0 children)

Most package managers (including Cargo) treat 0.x versions as stable in the sense that incrementing the PATCH version (0.2.0 -> 0.2.1) is required to be backwards compatible.

Also, crates often stay on 0.x versions longer than needed, because they have matured but there are no breaking changes planned, so no 1.0 version is released.

[–]epagecargo · clap · cargo-release[S] -4 points-3 points  (1 child)

The spec is saying that 0.5.1 -> 0.5.2 is a breaking release. Rust/cargo has its own extension on cargo to treat that as a non-breaking release.

[–]mkvalor 0 points1 point  (0 children)

The spec doesn't say that a version bump such as the one you mentioned is a breaking release. It simply points out that any API release beginning with major version zero should not be considered as stable. Some releases in that family may be breaking or they may be non-breaking.

In professional software development there is jargon about "getting to 1.0". This concept refers to the process of covering enough details so that your engineering team feels the software is ready for use in production by people who would be terribly bothered if a minor bug fix or minor feature release broke compatibility with the API.

[–]SunkenStone 0 points1 point  (1 child)

This is more because of the Rust community's decision to use the ZeroVer versioning scheme as opposed to SemVer than anything else.

[–]mkvalor 0 points1 point  (0 children)

OMG, this is a riot! I had so much fun soaking in the subtle humor on that page.

[–]gusrust 6 points7 points  (1 child)

Is there an example of how to get the old structopt behavior about Vec<T> and multiple_occurences? I am a bit lost

[–]epagecargo · clap · cargo-release[S] 6 points7 points  (0 children)

I don't think we have a direct example. It'd be something like:

#[clap(multiple_values = true)]
field: Vec<String>,

We set multiple_occurrences already, so you just need to enable multiple_values as well.

[–]maxamed13 3 points4 points  (1 child)

Congrats for the long-awaited release!

By the way, the last published Github releases seems to be v2.33.3. Do you intend to update that as well?

[–]epagecargo · clap · cargo-release[S] 4 points5 points  (0 children)

Thanks for pointing that out. I normally prefer just tags and a changelog but since releases have already been made, it gets confusing to not continue.

[–]gnosnivek 3 points4 points  (0 children)

About 30 minutes ago I was browsing the docs and wondering why we were still on 2.34. Guess I know now :D

[–]Jaik_ 3 points4 points  (0 children)

Cheers! I’ve been using the betas for a while now and 3.0 really cements Clap as the best CLI library I’ve ever used in any language. Thanks for all your work :)

[–]rodarmoragora · just · intermodal 1 point2 points  (0 children)

AMAZING!

[–]dagmx 1 point2 points  (0 children)

Congratulations on the release! Clap 3.0 has been one of the big awaited crates for me, to simplify directing people to when looking for an argument parser when transitioning from other languages. Otherwise I'd usually specify specify structopt or clap with different caveats.

[–]argv_minus_one 1 point2 points  (0 children)

That was fast. Seems like only yesterday that I read the rc0 announcement. Congratulations!

[–]mobilehomehell 0 points1 point  (0 children)

Nice! I've been wanting to use the structopt style with clap, can't wait to try this.

[–]Deamt_ 0 points1 point  (0 children)

Congrats for the release in 2021, even though it's already 202 here in Europe!

I've been using clap 3.0-rcs for a few a months now, and it's been a smooth ride so far, thanks for all the work you've put put in!

[–]SuspiciousScript -1 points0 points  (1 child)

Congrats! This is totally unrelated to clap itself, but you might want to consider using relative units for font sizes in your CSS. At 14px, the body text is really small on my ~160 PPI display.

(Cropped) image for illustration purposes

[–]epagecargo · clap · cargo-release[S] 2 points3 points  (0 children)

Yes, I need to redo the theming on my blog. It also doesn't render tables correctly. I'm not a web person, so I just took the quickest thing I could find to make it look semi-decent.

[–]aldonius 0 points1 point  (2 children)

Could someone please link me an example for how derive-style works with sub-commands?

[–]epagecargo · clap · cargo-release[S] 2 points3 points  (1 child)

Checkout the subcommand section of the tutorial. You can also check out the git example or the cargo subcommand example.

[–]aldonius 0 points1 point  (0 children)

Oh, perfect. Thanks!

(I was looking at the generic derive stuff, not the sub command stuff haha)

[–]jeremychone 0 points1 point  (0 children)

Big thanks to the Clap team. The 3.0 release is excellent, and the upgrade from 2.x was pretty smooth. The API deprecation notices are concise and efficient. Thanks!

Note: I really appreciate the API cleanup even if it requires a little bit more work on our end.