bmjames / scala-optparse-applicative

Scala port of Paolo Capriotti's optparse-applicative library. This repository is no longer maintained; newer versions exist in this fork: https://github.com/xuwei-k/optparse-applicative
BSD 3-Clause "New" or "Revised" License
72 stars 9 forks source link

Parser[T] is invariant of T #2

Closed erikkaplun closed 8 years ago

erikkaplun commented 9 years ago

Is that a necessity? It's necessitating type declarations when using subcommands, e.g.:

sealed trait Cmd
case class DeployCmd(...)  extends Cmd
case class RestartCmd(...) extends Cmd

val deployCmd: Parser[Cmd]  = subparser(command("deploy", ...))
val restartCmd: Parser[Cmd] = subparser(command("restart", ...))

val subcmd = deployCmd <+> restartCmd  

The above will fail to compile if either one of deployCmd or restartCmd aren't declared as Parser[Cmd].

But then again I've been told that variance causes other, more serious, type inference issues, so if that's the case I'm willing to live with the explicit type annotations.

bmjames commented 9 years ago

In your example, I don't think that making Parser covariant will solve the problem; there will still be a problem at the call site of <+>, whose definition does not admit any variance.

Furthermore, even with a covariant Parser, subtyping can still cause inference pain when you use command, because its return type is necessarily invariant in T (it contains a value of type CommandFields[T] => CommandFields[T]).

Adding variance to Parser may be harmless, but I'm hesitant to do so, because I haven't fully thought it through, and I haven't yet hit a significant problem that it would solve.

My feeling is that I'd prefer simply to have an invariant Parser, than to solve a few inference problems but leave others lurking in corners of the API.