Skip to content
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

Allow commands to return a Task<RuntimeResult> #466

Merged
merged 3 commits into from Jun 29, 2017

Conversation

FiniteReality
Copy link
Member

This allows bot developers to centralize command result logic by using result data whether the command was successful or not.

Example usage:

var _result = await Commands.ExecuteAsync(context, argPos);
if (_result is RuntimeResult result)
{
    await message.Channel.SendMessageAsync(result.Reason);
}
else if (!_result.IsSuccess)
{
    // Previous error handling
}

The RuntimeResult class can be subclassed too, for example:

var _result = await Commands.ExecuteAsync(context, argPos);
if (_result is MySubclassedResult result)
{
    var builder = new EmbedBuilder();
    for (var pair in result.Data)
    {
        builder.AddField(pair.Key, pair.Value, true);
    }
    await message.Channel.SendMessageAsync("", embed: builder);
}
else if (_result is RuntimeResult result)
{
    await message.Channel.SendMessageAsync(result.Reason);
}
else if (!_result.IsSuccess)
{
    // Previous error handling
}

@foxbot
Copy link
Member

foxbot commented Jan 6, 2017

What's the use-case for this?

I'm not seeing how this is any better than throwing a custom exception and pattern-matching the type of the exception.

@khionu
Copy link
Contributor

khionu commented Jan 6, 2017

This was discussed in the Dev Guild.

@foxbot
Copy link
Member

foxbot commented Jan 6, 2017 via email

@khionu
Copy link
Contributor

khionu commented Jan 6, 2017

TL;DR, custom errors, or passing any data from the commands. Good for any PostCommand Logic

@Auralytical Auralytical added this to the 1.0 milestone Apr 3, 2017
@FiniteReality FiniteReality added this to In Progress in Commands Apr 25, 2017
@FiniteReality FiniteReality mentioned this pull request Apr 29, 2017
5 tasks
@@ -249,7 +249,7 @@ private static bool IsValidModuleDefinition(TypeInfo typeInfo)
private static bool IsValidCommandDefinition(MethodInfo methodInfo)
{
return methodInfo.IsDefined(typeof(CommandAttribute)) &&
methodInfo.ReturnType == typeof(Task) &&
(methodInfo.ReturnType == typeof(Task) || methodInfo.ReturnType == typeof(Task<RuntimeResult>)) &&
Copy link
Contributor

@Joe4evr Joe4evr May 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this PR (allegedly) still needs a discussion, I'm throwing this note in here: this check won't work entirely well when people want to return a Task<CustomRuntimeResult>.

Disregard this, I know where this decision is coming from now.

@foxbot foxbot self-requested a review June 16, 2017 15:45
break;
{
var task = _action(context, args, map);
var returnTask = task as Task<RuntimeResult>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use c#7 match block

[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class RuntimeResult : IResult
{
private RuntimeResult(CommandError? error, string reason)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be protected for allowing subclassed RuntimeResults.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙃 I'm sure I managed to subclass this when I tested it originally, good catch though.

@foxbot foxbot added this to Vetted PRs (1.0) in Library Development Jun 28, 2017
{
await Module.Service._cmdLogger.DebugAsync($"Executing {GetLogText(context)}").ConfigureAwait(false);
try
{
await _action(context, args, services).ConfigureAwait(false);
var task = _action(context, args, services);
if (task is Task<IResult> returnTask)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be crazy, but this doesn't seem like it actually works. A quick test with this code seems to print Nope every time.
It's possible to do if (task is Task<RuntimeResult> resultTask) instead, and not need the second check.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does work, but probably not for users using command builders. Whoops.

The reason why I needed to return Task is because of ModuleClassBuilder's Callback code: it returns a Task, and unfortuantely due to contravariance not working the way I wanted it to, it would never trip the condition.

FiniteReality and others added 3 commits June 29, 2017 22:05
This allows bot developers to centralize command result logic by
using result data whether the command as successful or not.

Example usage:
```csharp
var _result = await Commands.ExecuteAsync(context, argPos);
if (_result is RuntimeResult result)
{
    await message.Channel.SendMessageAsync(result.Reason);
}
else if (!_result.IsSuccess)
{
    // Previous error handling
}
```

The RuntimeResult class can be subclassed too, for example:
```csharp
var _result = await Commands.ExecuteAsync(context, argPos);
if (_result is MySubclassedResult result)
{
    var builder = new EmbedBuilder();
    for (var pair in result.Data)
    {
        builder.AddField(pair.Key, pair.Value, true);
    }
    await message.Channel.SendMessageAsync("", embed: builder);
}
else if (_result is RuntimeResult result)
{
    await message.Channel.SendMessageAsync(result.Reason);
}
else if (!_result.IsSuccess)
{
    // Previous error handling
}
```
It never really made sense to have it instantiable in the first place,
frankly.
@Auralytical Auralytical merged commit 74f6a4b into discord-net:dev Jun 29, 2017
@foxbot foxbot removed this from 1.0.0 in Library Development Jun 29, 2017
@FiniteReality FiniteReality deleted the feature/command-returns branch June 30, 2017 13:05
@foxbot foxbot moved this from In Progress (1.0) to Implemented/Fixed in Commands Aug 2, 2017
FiniteReality added a commit to FiniteReality/Discord.Net that referenced this pull request May 5, 2018
* Allow commands to return a Task<RuntimeResult>

This allows bot developers to centralize command result logic by
using result data whether the command as successful or not.

Example usage:
```csharp
var _result = await Commands.ExecuteAsync(context, argPos);
if (_result is RuntimeResult result)
{
    await message.Channel.SendMessageAsync(result.Reason);
}
else if (!_result.IsSuccess)
{
    // Previous error handling
}
```

The RuntimeResult class can be subclassed too, for example:
```csharp
var _result = await Commands.ExecuteAsync(context, argPos);
if (_result is MySubclassedResult result)
{
    var builder = new EmbedBuilder();
    for (var pair in result.Data)
    {
        builder.AddField(pair.Key, pair.Value, true);
    }
    await message.Channel.SendMessageAsync("", embed: builder);
}
else if (_result is RuntimeResult result)
{
    await message.Channel.SendMessageAsync(result.Reason);
}
else if (!_result.IsSuccess)
{
    // Previous error handling
}
```

* Make RuntimeResult's ctor protected

* Make RuntimeResult abstract

It never really made sense to have it instantiable in the first place,
frankly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Commands
Implemented/Fixed
Development

Successfully merging this pull request may close these issues.

None yet

5 participants