-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Subcommands #12
Comments
How do you propose handling subcommands with different arguments? Let's say you have a |
It wouldn't be possible with the proposed method - at least not fully. That would be possible with optional types, i.e. the overall command type would be This is where I'd lean towards the mentioned overloaded commands - which might be better long term anyway. |
Since the library is generating a lot of if statements anyway, what's the issue with adding a subcommand API I suggested earlier? public class ConfCommand: ICommand
{
[SubCommand]
public async ValueTask Set(Context ctx, string key, string value)
{
}
[SubCommand(Default=True)]
public async ValueTask Show(Context ctx, string key = "")
{
}
} |
@soumil07 so, the reason why this wasn't specifically considered is because the current setup avoids "floating methods" - there is a specific interface you implement ( However, I've come to realize, we can have the best of both worlds. Consider: public class ConfCommand : ICommand<string, string>, ICommand<string>
{
[SubCommand("set")]
public async ValueTask RunAsync(string key, string value) {} // this is required to exist because of the implementation of ICommand<string, string>
[SubCommand("show")] // and this, because of the implementation of ICommand<string>
public async ValueTask RunAsync(string key) {}
} Now, this leaves only one "problem" which is you cannot have two (or more) subcommands with the exact same usage. Though, honestly, if you have two subcommands with the exact same usage, IMO they aren't subcommands, that's just a command with two options. CC @kyranet |
Hint, two subcommands with the same args but entirely different behaviour:
|
And this is where I'd argue really, that isn't two "different" commands, that's just a command with two different options public class ConfCommand : ICommand<ConfType, string, string>
{
public async ValueTask RunAsync(ConfType type, string key, string value)
{
return type switch
{
ConfType.Set => SetAsync(key, value),
ConfType.Remove => RemoveAsync(key, value)
}
}
} this also encourages users to move more logic outside of commands, and abstract them into contained classes/methods, for better testbility. |
Realistically, the only "use" for subcommands I can see is a command under the same name, that takes two different usages' - if it has the same name, and has the same usage, why not just handle that yourself with a simple enum/switch case? It also means you don't have two different sets of logic pushed into a single method - which again, is great for code readability and testing. |
After some internal discussion in discord with @kyranet - more complex types (i.e. what if there are several subcommands, some share a common type, and some don't) can't really be handled by this. Some more thought is definitely needed. |
How do we handle subcommands? Right now I'm leaning towards not handling them. One of the main goals of this library is simplicity - and it isn't hard to handle subcommands user-end either:
Obviously this is a simple example - and it does pose one issue: all subcommands need to have the same usage. Another idea is "overloaded" commands, where the command is picked based on the name and the usage - so you can have several commands with the same name, but different usages'. This could be annoying for code duplication, however, and would likely be bad for performance.
The text was updated successfully, but these errors were encountered: