Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(derive): Specify defaults by native expressions #2635

Merged
merged 1 commit into from
Aug 13, 2021

Conversation

epage
Copy link
Member

@epage epage commented Jul 28, 2021

Right now

  • default_value="something" is a raw method
  • default_value uses native types

This commit splits the meanings

  • default_value="something" is a raw method
  • default_value_t uses T::default()
  • default_value_t=expr uses an expression that evaluates to T

This is meant to mirror the value_of / value_of_t API.

At the moment, this is limited to T: Display to work with clap's
default system. Something we can look at in the future is a way to
loosen that restriction. One quick win is to specialize when arg_enum
is set. The main downside is complicating the processing of attributes
because it then means we need some processed before others.

Since this builds on claps existing default system, this also means
users do not get any performance gains out of using default_value_t,
since we still need to parse it but we also need to convert it to a
string.

Fixes #1694

@epage
Copy link
Member Author

epage commented Jul 28, 2021

@pksunkara FYI looks like this is another sporadic failure: https://github.com/clap-rs/clap/runs/3183588763?check_suite_focus=true

@epage
Copy link
Member Author

epage commented Jul 30, 2021

@pksunkara CI failure is in src/build/app/mod.rs which this PR doesn't touch

@epage epage closed this Jul 30, 2021
@epage epage reopened this Jul 30, 2021
Copy link
Member

@pksunkara pksunkara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but we don't really need default_value_t. Everything can be under default_value.

#[derive(Clap, PartialEq, Debug)]
struct Opt {
#[clap(default_value)]
#[clap(default_value = "0")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use something other than 0 or 1 here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is it you feel missing with using 0/1 that I should cover?

For the raw case, "0" is non-default. 1 would never show up from defaults.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just we are testing for 0 & 1 and I wanted this to be "2"

@epage
Copy link
Member Author

epage commented Aug 9, 2021

Looks good, but we don't really need default_value_t. Everything can be under default_value.

Could you clarify what you intend for how all of this would work under default_value?

We need to distinguish intent between a raw default and a typed default, Personally, I'm unsure of doing that based purely on string literal vs not string literal which is my only guess as to what you intend.

@pksunkara
Copy link
Member

Yup, since these are macros, we can use the freedom of syntax.

Let's do

  • default_value="something" is a raw method
  • default_value uses T::default()
  • default_value=expr uses an expression that evaluates to T

@epage
Copy link
Member Author

epage commented Aug 11, 2021

Yup, since these are macros, we can use the freedom of syntax.

Let's do

* `default_value="something"` is a raw method

* `default_value` uses `T::default()`

* `default_value=expr` uses an expression that evaluates to `T`

default_value="something" is an expression. Overloading intent like this is generally
confusing and brittle.

@pksunkara
Copy link
Member

"raw method" is nomenclature in clap derive that denotes it is simply forwarded to clap.

Overloading intent like this is generally confusing and brittle.

Hmm.. I do agree on that. But, that is what structopt has been doing and what default_value_t you did was doing too.

These attributes will be hardest to migrate for end users, which is why I was suggesting to keep the original default_value. And since we are already overloading it, let's just use it for =expr too.


Reference on how structopt behaves currently: https://docs.rs/structopt/0.3.22/structopt/#default-values


Btw, I removed the underlying issue from 3.0 milestone because I mistakenly tagged it originally.

@epage
Copy link
Member Author

epage commented Aug 13, 2021

what default_value_t you did was doing too.

My change does not have overloaded intent. default_value will exclusively work with pre-parsed data. default_value_t works exclusively with parsed data.

As I think we should make this breaking change, I think this is still relevant for 3.0. As I said, this makes clap more self-consistent and removes ambiguity which will help on-boarding. We have to weigh both migration and future adoption. As an end-user, this is relatively easy change to migrate to.

@pksunkara
Copy link
Member

I am now convinced. Let's remove the special case handling of DefaultValue then in this PR since it just gets forwarded to Method. We don't need this variant anymore.

Right now
- `default_value="something"` is a raw method
- `default_value` uses native types

This commit splits the meanings
- `default_value="something"` is a raw method
- `default_value_t` uses `T::default()`
- `default_value_t=expr` uses an expression that evaluates to `T`

This is meant to mirror the `value_of` / `value_of_t` API.

At the moment, this is limited to `T: Display` to work with clap's
default system.  Something we can look at in the future is a way to
loosen that restriction.  One quick win is to specialize when `arg_enum`
is set.  The main downside is complicating the processing of attributes
because it then means we need some processed before others.

Since this builds on `clap`s existing default system, this also means
users do not get any performance gains out of using `default_value_t`,
since we still need to parse it but we also need to convert it to a
string.

Fixes clap-rs#1694
@epage
Copy link
Member Author

epage commented Aug 13, 2021

PR updates include

  • Making the test parellels more obvious
  • Moving away from using a user-defined default that looks like a Default::default
  • Removed DefaultValue
  • Added an abort (with UI test) to help users migrate

abort!(name,
"`#[clap(default_value)` attribute (without a value) has been replaced by `#[clap(default_value_t)]`.";
help = "Change the attribute to `#[clap(default_value_t)]`";
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cargo-up should be able to handle this easily without us needing the abort. This should be deleted when I finish the structopt to clap upgrader then.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally would find this useful because I'm unlikely to download a special tool just to handle a library migration. The likelihood of downloading is proportionate to the number of CLIs I maintain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Specify defaults in terms of the underlying type rather than strings
2 participants