Can we talk about the API surface?

Yeah, it's not like that intention was lost on me. But everything one puts inside Repeat, aside from the run() method, is about how the command line should be formed by, and described to, users. I can't imagine, having already gathered so much code to describe the command syntax in this one type, wanting to keep any substantial command logic here. Separation of concerns, and all that.

That said, I see two ways to look at choosing this name:

  1. The library is about parsing command line syntax and dispatching to one or more handlers, so the thing called Repeat is basically a grammar for that syntax. In that sense, it can be parsed, but there's really no point in saying a grammar can be parsed, so I'd be considering names like CommandLine.Syntax if I was taking this angle (and I'd be renaming run() somehow appropriately, maybe onParsed(), dispatch(), recognized()…)

  2. The thing we're defining really is a “command:” it's a perfect example of the command pattern. But then, is it parseable? When viewed as a command, the parsing has already happened. If you want to introduce words that explain the declarations that end up forming the bulk of the code, CommandLine.Command seems like a great way to do that.

That's true because of the command line context. The notion of a “command line argument” is well-established and well-defined, and these have already been determined for us by the OS by the time our application starts running, and yes, they include the things (flags/switches/options/whatever) that start with hyphens. That's why I am fully in agreement with your discomfort about the use of @Argument

As you may know, I strongly believe comprehensibility is more important than an aesthetic concerns. In fact, IMO there's only a point in striving for consistency because sometimes it serves comprehensibility—and this isn't one of those cases.

That said, I am still hopeful we can reach a solution that combines consistency with comprehensibility. How bad would it be if all the names were clear and a bit longer? It's not like this is a DSL for a domain like regular expressions, linear algebra, or user interface construction, where information density is important because we need to be able to easily discern relationships among the elements. These things basically don't interact with one another, and the property wrapper name will typically get a whole line unto itself:

  • @StandaloneFlag
  • @ParameterFlag
  • @PositionalParameter

I used “Parameter” here because the things being declared are not "arguments:" the arguments are the things passed, and parsed, on the command-line. This may seem like a trivial difference, in part because many people don't know the difference between parameters and arguments, but Swift has already made conscious terminology decisions on the basis of this distinction: in function signatures we have “argument labels” and “parameter names.”

I'd rather not give up that easily. Being 100% honest, by the time I started writing this post I had already forgotten the difference between @Option and @Flag, and I was just using these names yesterday.

Thanks, I will. Now that I have some name ideas I'm comfortable with, I'd like to see how some of the more sophisticated examples look when using them. Are there specific examples you'd suggest for me?

2 Likes