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

default should be evaluated lazily(by passing a provider function, for example) #69

Open
minus199 opened this issue Sep 29, 2021 · 3 comments

Comments

@minus199
Copy link

Reffering to

  • kotlinx.cli.OptionsKt#default(kotlinx.cli.SingleNullableOption, T)
  • kotlinx.cli.OptionsKt#default(kotlinx.cli.MultipleOption<T,OptionType,kotlinx.cli.DefaultRequiredType.None>, java.util.Collection<? extends T>)

Example Use case - in order to resolve an option with a value that could be set from an enviroment variable, kotlinxcli will first need to get the already resolved value of the env var, and only then search the value inside args.
It means that:

  • the env var should always be set and with a valid value(which is wrong if we think about multiple ways to set a single option),
  • or that resolving against the existence of an env var should happen after the parse had finished.
Optional.ofNullable(maybeSomeOptionThatCouldBeFromEnvVar)
        .or { resolveTheEnvVarAndReturnNullIfNotFoud() }
        .orElseThrow { Exception("SomeOptionThatCouldBeFromEnvVar is required") }

If the default value would have been a provider function that only evaluates when the parser finds that the actual value is missing, it would be much easier to use and goes along side the approach we normaly see in kotlin(for example, a logger.info that accepts a function that returns a string).

There are a lot of cases where the desired behaviour is to compute the default value only if the user did not input anything specific and it seems pretty straight forward to implement inside this lib.

Hope that makes sense, cheers for all your hard and awesome work!

@LepilkinaElena
Copy link

If I understood you correctly, you want to use default method inside your logic application. kotlinx.cli is library that responsibility is to parse command line arguments and it operates only in command line terms. So default value is set if user doesn't provide any value in command line. Any other possibilities to set value (environment variable, value from file, etc.) is logic and responsibility of application.

@sifraser
Copy link

sifraser commented Apr 11, 2022

Same heading, different example. I have e.g.

val a by parser.argument(ArgType.String, "A")
val b by parser.option(ArgType.String, shortName = "-b", description = "B").default(a)

I get

Exception in thread "main" java.lang.IllegalStateException: Value for argument A isn't set. ArgParser.parse(...) method should be called before.
	at kotlinx.cli.ArgumentSingleValue.getValue(ArgumentValues.kt:121)

There should be some means for the default of b to be lazily evaluated so that we can use the values of other arguments, so I can do:

val b by parser.option(ArgType.String, shortName = "-b", description = "B").default { a }

My specific usecase is with specifying a root directory and then having default sub-directories.

@mrlem
Copy link

mrlem commented May 11, 2023

@sifraser a bit late of an answer, but this usecase seems impossible to solve by kotlinx-cli, as it needs to be able to compute all default values before user input for the --help.

Here's what I did for a close use case:

val DEFAULT_SUB_TOKEN = "<root>/subdirectory"

val root by parser.argument(ArgType.String, "root")
val sub by parser.argument(ArgType.String, "sub")
  .default(DEFAULT_SUB_TOKEN)
val subPolicy =
  get() = when (sub) {
    DEFAULT_SUB_TOKEN -> Relative
    else -> Absolute(sub)
  }

sealed interface SubPolicy {
  object Relative
  data class Absolute(val directoryPath: String)
}

This way, you get a decent default value being displayed in --help, and you can handle both cases as you wish in subsequent code.

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

No branches or pull requests

4 participants