
Swift: Announcing ArgumentParser - zdw
https://swift.org/blog/argument-parser/
======
paulddraper
One of my very, very, very favorite things about Python is argparse. [1]

Very few libraries creates its API so well as to transcend its origins
(JodaTime comes to mind).

* Node.js [2]

* Java/JVM [3]

* Go [4]

* Lua [5]

* C++ [6] [7]

It appears there is no Swift port.

That is unfortunate, because besides the basics (optionals, positions,
defaults, short and log options, auto generated docs, subcommands,
descriptions, repeating options), it lets you do argument groups, mutually
exclusive options, customizable help behavior, variable customization, custom
parsers/validators, options with multiple arguments. There's even Python
support for shell autocomplete library. [7].

(One potential limitation is that it is naturally dynamic, and not typesafe
like Swift's new ArgumentParser. IMO that is of relatively small practical
importance compared to its other features.)

It's both simple enough to get going, but sophisticated enough that I've never
wanted for anything. It's the first thing I look for when writing a CLI.

[1]
[https://docs.python.org/3/library/argparse.html](https://docs.python.org/3/library/argparse.html)

[2] [http://nodeca.github.io/argparse/](http://nodeca.github.io/argparse/)

[3] [https://argparse4j.github.io/](https://argparse4j.github.io/)

[4]
[https://github.com/akamensky/argparse](https://github.com/akamensky/argparse)

[5] [https://github.com/mpeterv/argparse](https://github.com/mpeterv/argparse)

[6] [https://github.com/jbms/argparse](https://github.com/jbms/argparse)

[7]
[https://github.com/mmahnic/argumentum](https://github.com/mmahnic/argumentum)

[8]
[https://pypi.org/project/argcomplete/](https://pypi.org/project/argcomplete/)

~~~
akvadrako
I can't stand argparse. It's like they tried their hardest to force you to be
imperative and prevent composability. For example, instead of being able to
define a parser for a subcommand and build a top-lever parser from that, you
need to do this:

    
    
        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers()
        a = subparsers.add_parser('a')
        a.add_argument('bar')
    

A better API would look more like this:

    
    
        Parser(Subparsers({
           'a': Parser(Arg('bar')),
        }))
    

On top of that it has a number of bugs in edge cases they refuse to document
or fix. For example, you can't have a subcommand that always collects all the
remaining arguments as-is. That's a pretty basic use-case when you want to
pass those arguments to another program.

~~~
paulddraper
Python is indeed an imperative language, along with the others I listed. (Your
proposal would indeed be at home in a functional language like LISP.)

But I reject the idea that imperative is bad. You can compose imperative
programming fine.

    
    
        def my_parser(parser):
            parser.add_argument('bar')
    
        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers()
        my_parser(subparsers.add_parser('a'))
        my_parser(subparsers.add_parser('a2'))
    

> you can't have a subcommand that always collects all the remaining arguments
> as-is.
    
    
        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers()
        a = subparsers.add_parser('a')
        a.add_argument('args', nargs='*')
    

That works just fine.

    
    
        ./example a arg1 arg2 arg3
    
        ./example a -- arg1 --look-ma-hyphens-arg2 arg3
    

If you're complaining about the double hyphen syntax....that's a universal
convention for UNIX-ish CLI positional arguments. Otherwise things get really
murky.

    
    
        ./example a --help
    

Did I want help on the `a` subcommand, or did I want to pass `--help` to the
`a` subcommand? The `--` syntax lets you distinguish.

~~~
nicoburns
> Python is indeed an imperative language, along with the others I listed.

JavaScript has functional origins, and in practice quite a bit of JavaScript
is written in a functional-lite style. As a JS developer, I find it quite
infuriating that Python doesn't support these patterns, as they make code a
lot more readable, and it seems to be a matter of principle rather than a
technical limitation.

------
wyager
If you haven't seen it, I consider the best-in-class argument parsing library
to be Optparse-Applicative. [https://github.com/pcapriotti/optparse-
applicative](https://github.com/pcapriotti/optparse-applicative)

It provides an applicative interface, which it turns out is very precisely
impedance-matched to the nature of command line arguments.

It also integrates nicely with e.g.
[https://hackage.haskell.org/package/optparse-
generic](https://hackage.haskell.org/package/optparse-generic) to
automatically derive command line parsers from data structures.

An example from a recent process of mine: [https://github.com/wyager/zfs-
backup/blob/master/src/Lib.hs](https://github.com/wyager/zfs-
backup/blob/master/src/Lib.hs) . You can see what the generated help text
looks like in the README.

The argument parser is automatically derived from the data structure
describing the commands available in my program, using optparse-generic. Some
extra type annotations on the command data structure provide the detailed
document text.

Of course, you don't have to use the fancy auto-generation stuff if you don't
want to. Writing optparse-applicative parsers by hand is very pleasant as
well. Here is the argument parser code for my website's server:
[http://paste.best/p/22_rCSCen8M=](http://paste.best/p/22_rCSCen8M=)

------
rkagerer

        @Argument(help: "The highest value to pick.")
        var highValue: Int
        
        func validate() throws {
            guard highValue >= 1 else {
                throw ValidationError("'<high-value>' must be at least 1.")
            }
        }
    

Not saying there's anything wrong with this. But I wrote a generic command
line parsing library for C# some years back, and simple validators like min /
max values were handled with attributes. The elegance was that limits were
defined in exactly one place in the code, and error messages like that
manually constructed above were synthesized automatically. (Of course you
could override with your own validation function for bespoke cases)

------
friday99
Error: The value 'ZZZ' is invalid for '<high-value>'

That is an awful default error for validating the type. The program knows it
failed to parse as an Int but doesn't tell you anything about that.

Error: The value 'ZZZ' is invalid for '<high-value>' of type Int

Also, the help should automatically tell you the expected types as well.

ARGUMENTS: <high-value>: Int The highest value to pick.

~~~
thedirt0115
There's an issue open for this, so they'll probably have it pretty soon:
[https://github.com/apple/swift-argument-
parser/issues/8](https://github.com/apple/swift-argument-parser/issues/8)

------
cobbal
Cool! I've recently started writing many of my shell scripts in swift
[shameless plug], but nice command line argument processing was something I
wasn't looking forward to tackling. Now it looks like I won't have to :)

[shameless plug]:
[https://github.com/cobbal/swsh](https://github.com/cobbal/swsh)

Description:

A shell-scripting library for Swift, inspired by scsh.

swsh makes writing shell scripts more fun by exchanging bash (or similar) for
a better thought-out language like Swift. In the process, a small amount of
conciseness is traded for better quoting, error handling, and access to
libraries.

------
uep
I'm somewhat clueless on this front. How usable is Swift outside of Apple
OSes? I recall reading here that the language toolchain is broken all the time
for other platforms. Is that still the case?

------
vi4m
Looks like very nice use case for Property Wrappers demonstration.

------
tempodox
I can see it now. Swift will be the first actually code-less language. Just
@pile @up @all @necessary @magic @keywords, and your program is complete.

Seriously, instead of doing things actually worth mentioning as programming
language development, they kill time with collecting cute magic tricks? Swift
could have been interesting but featurism and mission creep make it a bag of
complicated magic even worse than C++. At least C++ templates let me build my
own magic. I have a strong suspicion that I will never use Swift voluntarily.

~~~
w0utert
I don’t understand this comment. There is nothing magic there, the @ is just
syntax for using property wrappers, which you can write and document yourself,
they are a language feature. The argument parser is just a swift library that
uses this feature. In particular, @Argument is not a keyword.

------
alexashka
Can we please have a 'New Version', 'Old Version' comparison, side by side.

If this is an improvement, why are you _telling_ me instead of _showing_ me?

Personally, the problem is command line tools, not argument parsing. Why would
anyone create a command line tool instead of a GUI that only lets you enter
the correct set of arguments that go together, grouped into a coherent UI?

The end result should be a json. We all know how to parse json in Swift and
every other language in existence.

~~~
paulddraper
CLI tools exist for composibility.

How many lines non-ignored lines are in my git worktree?

    
    
       git ls-files -coz --exclude-standard | xargs -0 cat 2>/dev/null -- | wc -l --
    

How would you ever create a GUI with that much flexibility?

~~~
ken
Any ETL tool can do tasks like this. It probably has a terrible user
interface, but they're enterprise tools and enterprise tools tend to be
terrible, regardless of the style or task.

You're right that most GUIs don't tend to be composable -- but that's a
function of how they're written, not an inherent limitation of GUIs. There's
nothing fundamental about the VT100-style interface that makes it optimal for
composition. And GUIs potentially offer some huge benefits, like not having to
guess at what's flowing through the pipelines, or having a less painful way to
deal with quoting/escaping, or offering an alternative to cryptic flags for
configuring operations.

Screen editors used to get the same scorn. You probably haven't heard the term
"screen editor" in a few decades because _every_ editor today is a screen
editor. Once they acquired most of the flexibility of line editors, it turned
out that nobody actually preferred line editors.

People want composability, and you can do that in a screen editor better than
a line editor -- and a GUI better than a terminal. You just have to have
designers who care about it.

