remkop / picocli

Picocli is a modern framework for building powerful, user-friendly, GraalVM-enabled command line apps with ease. It supports colors, autocompletion, subcommands, and more. In 1 source file so apps can include as source & avoid adding a dependency. Written in Java, usable from Groovy, Kotlin, Scala, etc.
https://picocli.info
Apache License 2.0
4.92k stars 423 forks source link

Strict null handling mode #2334

Open Krever opened 2 months ago

Krever commented 2 months ago

Could picocli have an alternative opt-in mode where all options and parameters are considered required, unless typed as Optional or multivalue? The goal is to not use nulls at all.

I sketched the following model transformer (in scala) that seems to work in a simple scenario.

class StrictOptionsTransformer extends IModelTransformer {
  override def transform(commandSpec: Model.CommandSpec): Model.CommandSpec = {
    val argSpecClz = classOf[ArgSpec]
    val requiredField = argSpecClz.getDeclaredField("required")
    requiredField.setAccessible(true)
    val toBeReAdded = commandSpec
      .options()
      .asScala
      .toList // makes a copy, so we don't ConcurrentModificationException
      .foreach(spec => {
        val required = !(spec.typeInfo().isOptional || spec.typeInfo().isMultiValue)
        if (required) {
          requiredField.set(spec, true)
          // remove and add is required to register as required arg
          commandSpec.remove(spec)
          commandSpec.add(spec)
        }
      })
    commandSpec
  }
}

(I'm not suggesting this as an implementation baseline of the new mode, I expect it would need to be something much more sophisticated).

remkop commented 2 months ago

Not sure that I follow your intention.

You could just define each option and positional parameter as required. Why then would you need the model transformer?

Alternatively, you could have validation at the beginning of your run or call method to assert that all options are non-null.

remkop commented 2 months ago

Not sure that I follow your intention.

You could just define each option and positional parameter as required. Why then would you need the model transformer?

Alternatively, you could have validation at the beginning of your run or call method to assert that all options are non-null.

Krever commented 2 months ago

You could just define each option and positional parameter as required.

Definitely, but it introduces places for mistakes. For worlds without nulls (e.g. Scala or null-prohibited Java), the information about "requiredness" is then encoded in two places: types and required flag. My intention is to keep it only encoded via types, so in "null safe mode" everything that is not Optional is required by default.

Alternatively, you could have validation at the beginning of your run or call method to assert that all options are non-null.

I haven't thought of that. If there is a plugin point at which this can be done generically, it might work, although its still a bit different. Validation will be case by case, while the transformer ensures strictness at spec and parser level.

remkop commented 2 months ago

Sorry I am not convinced that this should be done at the library level. At this point, applications have to do their own coding to ensure non-null-ness for the options and parameters.

Krever commented 2 months ago

Sure, that's fine with me. There is a solution available in the user space (the transformer) hence no need to have it on the library level. Maybe more voices from the community will join the discussion in the future. Feel free to close the ticket AFAIC.