• azertyfun@sh.itjust.works
    link
    fedilink
    arrow-up
    18
    arrow-down
    1
    ·
    6 days ago

    Counterpoint: Yes, parse don’t validate, but CLIs should not be dealing with dependency management.

    I love Python’s argparse because:

    • It’s “Parse, don’t validate” (even supports FileType as a target)
    • It enforces or strongly encourages good CLI design
      • Required arguments should in most situations be positional arguments, not flags. It’s curl <URL> not curl --url <URL>.
      • Flags should not depend on each other. That usually indicates spaghetti CLI design. Don’t do server --serve --port 8080 and server --reload with rules for mix-and-matching those, do server serve --port 8080 and server reload with two separate subparsers.
      • Mutually exclusive flags sometimes make sense but usually don’t. Don’t do --xml --json, do -f [xml|json].
      • This or( pattern of yours IMO should always be replaced by a subparser (which can use inheritance!). As a user the options’ data model should be immediately intuitive to me as I look at the --help and having mutually exclusive flags forces the user to do the extra work of dependency management. Don’t do server --env prod --auth abc --ssl, do server serve prod --auth abc --ssl where prod is its own subparser inheriting from AbstractServeParser or whatever.

    Thinking of CLI flags as a direct mapping to runtime variables is the fundamental mistake here I think. A CLI should be a mapping to the set(s) of behavior(s) of your application. A good CLI may have mandatory positional arguments but has 0 mandatory flags, 0 mutually exclusive flags, and if it implements multiple separate behaviors should be a tree of subparsers. Any mandatory or mutually exclusive flags should be an immediate warning that you’re not being very UNIX-y in your CLI design.

  • Serinus@lemmy.world
    link
    fedilink
    arrow-up
    5
    arrow-down
    1
    ·
    7 days ago

    I’m not sure the value added is worth the extra layer.

    I guess my command line options just aren’t all that complicated.

  • TehPers@beehaw.org
    link
    fedilink
    English
    arrow-up
    2
    ·
    7 days ago

    I like the concept, and it’s great in TS. Unfortunately, not as doable in other languages.

    I’m a bit curious if it’s possible to extend clap to do this in Rust though (specifically mutually-exclusive arg groups).

      • TehPers@beehaw.org
        link
        fedilink
        English
        arrow-up
        7
        ·
        7 days ago

        This doesn’t represent the mutual exclusivity through the type system (which is what the article is all about).

        I love clap and I use it a lot, but the only way to represent the exclusivity through the type system in Rust is through an enum.

        • ExFed@programming.dev
          link
          fedilink
          arrow-up
          4
          ·
          7 days ago

          Agreed. As nice as clap is, it’s not a combinator. Parser combinators have a the really nice feature of sharing the same “shape” as the data they parse, which makes them trivial to generate from a schema … or to just use them to represent your schema in the first place ;) .

      • TehPers@beehaw.org
        link
        fedilink
        English
        arrow-up
        4
        ·
        7 days ago

        Mentioned this to the other commenter, but this doesn’t use the type system to enforce the mutual exclusivity constraint. In Rust, the main way to do that via the type system is through enums.

        • Ephera@lemmy.ml
          link
          fedilink
          English
          arrow-up
          2
          ·
          7 days ago

          Ah, fair enough. Not sure how to do that then.

          I was gonna say, I feel like the current method does a good enough job documenting that validation has happened, but I guess you do want it reflected in the structure of the type, so that the code that takes the information from the struct can safely make the assumption that some of the options don’t exist. And then, yeah, it would be nice to not need a separate parsing step for that.