dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.42k stars 4.75k forks source link

[API Proposal]: Async overloads of `Console.Write[Line]` #104182

Closed colejohnson66 closed 4 months ago

colejohnson66 commented 4 months ago

Background and motivation

Async overloads of Console.Write[Line] are not present. They should be added to avoid blocking in async methods.

API Proposal

Instead of exposing the subset of APIs on TextWriter, this contains the APIs available on Console that just forward to Out.WriteX

namespace System;

public static class Console
{
    public static Task WriteAsync(bool value);
    public static Task WriteAsync(char value);
    public static Task WriteAsync(char[]? buffer);
    public static Task WriteAsync(char[]? buffer, int index, int count);
    public static Task WriteAsync(decimal value);
    public static Task WriteAsync(double value);
    public static Task WriteAsync(float value);
    public static Task WriteAsync(int value);
    public static Task WriteAsync(long value);
    public static Task WriteAsync(object? value);
    public static Task WriteAsync(string? value);
    public static Task WriteAsync(uint value);
    public static Task WriteAsync(ulong value);

    public static Task WriteLineAsync(bool value);
    public static Task WriteLineAsync(char value);
    public static Task WriteLineAsync(char[]? buffer);
    public static Task WriteLineAsync(char[]? buffer, int index, int count);
    public static Task WriteLineAsync(decimal value);
    public static Task WriteLineAsync(double value);
    public static Task WriteLineAsync(float value);
    public static Task WriteLineAsync(int value);
    public static Task WriteLineAsync(long value);
    public static Task WriteLineAsync(object? value);
    public static Task WriteLineAsync(string? value);
    public static Task WriteLineAsync(uint value);
    public static Task WriteLineAsync(ulong value);

    // these ones could probably be tossed in favor of interpolated strings decaying to `string`
    public static Task WriteAsync([StringSyntax("CompositeFormat")] string format, object? arg0);
    public static Task WriteAsync([StringSyntax("CompositeFormat")] string format, object? arg0, object? arg1);
    public static Task WriteAsync([StringSyntax("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2);
    public static Task WriteAsync([StringSyntax("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2, object? arg3);
    public static Task WriteAsync([StringSyntax("CompositeFormat")] string format, params object?[] args);
    public static Task WriteLineAsync([StringSyntax("CompositeFormat")] string format, object? arg0);
    public static Task WriteLineAsync([StringSyntax("CompositeFormat")] string format, object? arg0, object? arg1);
    public static Task WriteLineAsync([StringSyntax("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2);
    public static Task WriteLineAsync([StringSyntax("CompositeFormat")] string format, object? arg0, object? arg1, object? arg2, object? arg3);
    public static Task WriteLineAsync([StringSyntax("CompositeFormat")] string format, params object?[] args);
}

API Usage

Essentially, this would prevent blocking of work while waiting for the console output to complete.

Task? t = null;
while (NeedToDoWork())
{
    if (t is not null)
        await t; // wait for previous write to finish
    t = Console.WriteLineAsync("Starting next task.");
    DoWork();
}

Alternative Designs

I've opted to duplicate the current API surface of Console. A more limited alternative would be one where only the async methods present in TextWriter are exposed.

Alternatively, an analyzer that detects usage of Console.Write[Line] in asynchronous methods could suggest rewriting it to Console.Out.Write[Line]Async. However, the API surface of Console is different from that of TextWriter - only char/string-based overloads are present there.

Risks

Existing analyzers would now detect Console.Write[Line](...) in async methods and suggest rewriting to await Console.Write[Line]Async(...).

dotnet-policy-service[bot] commented 4 months ago

Tagging subscribers to this area: @mangod9 See info in area-owners.md if you want to be subscribed.

alexrp commented 4 months ago

Related: #299

stephentoub commented 4 months ago

Duplicate of https://github.com/dotnet/runtime/issues/299. Thanks.