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

[API Proposal]: Missing CompositeFormat features #85099

Closed
geeknoid opened this issue Apr 20, 2023 · 3 comments · Fixed by #85348
Closed

[API Proposal]: Missing CompositeFormat features #85099

geeknoid opened this issue Apr 20, 2023 · 3 comments · Fixed by #85348
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime blocking Marks issues that we want to fast track in order to unblock other important work

Comments

@geeknoid
Copy link
Member

geeknoid commented Apr 20, 2023

EDITED BY @stephentoub 4/24/2023:

  • I removed the suggested TryParse overload. I don't currently see the need.
  • I renamed the proposed property, but we can probably come up with a better name, too.
public class CompositeFormat
{
+    // Gets the minimum number of arguments that must be passed to a formatting operation using this CompositeFormat.
+    // Providing more than this is fine, but less than this will result in an exception during formatting.
+    public int RequiredArgumentCount { get; }
}

This is just exposing a number the implementation already has in a field.


Background and motivation

The new CompositeFormat functionality in .NET 8 is missing a few features which hampers its usability. It would be great to see these features introduced.

  • A property that returns the number of arguments required when trying to format a string. The specific scenario where we need this is in order to allow the user to specify how to format some output within a config file. In our redaction logic, the customer can decide to format the output as simply "{0}" which means no redaction, or "REDACTED", or maybe "redacted:{0}". Whatever the customer wants. As we parse the format string, we need to know that the user specify either one argument value or none, so that we can produce a meaningful error message and we call the ultimate formatting function with the right number of args.

  • Return meaningful error messages. Right now, parsing composite format strings will return a single "invalid format" error. We have giant megabyte-sized format strings, and getting a single "you did something bad, but we're not telling you what it is" error message isn't a good UX. Our existing parser has error messages like $"Dangling }} in format string at position {pos}" or
    $"Missing argument index in format string at position {pos}". Ideally, the exception text for the Parse function should be refined to help users solve their problem, and the TryParse function should similarly return this error text.

API Proposal

namespace System.Text;

public class CompositeFormat
{
    /// <summary>
    /// Gets the number of arguments needed to successfully format this instance.
    /// </summary>
    public int NumArgumentsNeeded { get; }

    /// <summary>
    ///  Parses a format string and produces a high-quality error string in case of malformed input.
    /// </summary>
    public static bool TryParse([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string? format, [NotNullWhen(true)] out CompositeFormat? compositeFormat, [NotNullWhen(false)] string? error);

API Usage

    if (CompositeFormat.TryParse(formatStringFromConfig, out var cf, out var error);
    {
        if (cf.NumArgumentsNeeded != 0 && cf.NumArgumentsNeeded != 1)
        {
            logger.LogError($"Invalid number of arguments in format string, expecting 0 or 1 arguments but got {cf.NumArgumentsNeeded}");
            return false;
        }
    }
    else
    {
        logger.LogError($"Malformed format string: {error}");
        return false;
    }

    if (cf.NumArgumentsNeeded == 0)
    {
        return string.Format(cf);
    }

    return string.Format(cf, argToFormat);

Alternative Designs

No response

Risks

No response

@geeknoid geeknoid added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Apr 20, 2023
@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Apr 20, 2023
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Apr 20, 2023
@stephentoub
Copy link
Member

stephentoub commented Apr 20, 2023

As I stated offline, I don't see the benefit of such a TryParse (and frankly the existing TryParse is a little suspect but it follows a common pattern so I'm ok with it). The whole point of CompositeFormat is to create it rarely and do more expensive lifting once to avoid expense on every formatting. If you're creating them with such frequency with erroneous input that an exception is prohibitive, you're using it wrong. It definitely shouldn't be used as in your usage example where it's created, used once, and thrown away.

We can certainly improve the error message; it's just using the same parsing string.Format was already using and inherited its lack of details.

I'm fine exposing the number of arguments needed. But note as well that just like the existing string.Format, you can always provide more arguments than are needed, so in your usage example you don't need that if check at the end... just always pass the argument you have and it'll be used if needed and ignored if not.

@stephentoub stephentoub added api-ready-for-review API is ready for review, it is NOT ready for implementation area-System.Runtime blocking Marks issues that we want to fast track in order to unblock other important work and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged New issue has not been triaged by the area owner needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Apr 24, 2023
@stephentoub stephentoub self-assigned this Apr 24, 2023
@ghost
Copy link

ghost commented Apr 24, 2023

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

Issue Details

EDITED BY @stephentoub 4/24/2023:

  • I removed the suggested TryParse overload. I don't currently see the need.
  • I renamed the proposed property, but we can probably come up with a better name, too.
public class CompositeFormat
{
+    // Gets the minimum number of arguments that must be passed to a formatting operation using this CompositeFormat.
+    // Providing more than this is fine, but less than this will result in an exception during formatting.
+    public int RequiredArgumentCount { get; }
}

This is just exposing a number the implementation already has in a field.


Background and motivation

The new CompositeFormat functionality in .NET 8 is missing a few features which hampers its usability. It would be great to see these features introduced.

  • A property that returns the number of arguments required when trying to format a string. The specific scenario where we need this is in order to allow the user to specify how to format some output within a config file. In our redaction logic, the customer can decide to format the output as simply "{0}" which means no redaction, or "REDACTED", or maybe "redacted:{0}". Whatever the customer wants. As we parse the format string, we need to know that the user specify either one argument value or none, so that we can produce a meaningful error message and we call the ultimate formatting function with the right number of args.

  • Return meaningful error messages. Right now, parsing composite format strings will return a single "invalid format" error. We have giant megabyte-sized format strings, and getting a single "you did something bad, but we're not telling you what it is" error message isn't a good UX. Our existing parser has error messages like $"Dangling }} in format string at position {pos}" or
    $"Missing argument index in format string at position {pos}". Ideally, the exception text for the Parse function should be refined to help users solve their problem, and the TryParse function should similarly return this error text.

API Proposal

namespace System.Text;

public class CompositeFormat
{
    /// <summary>
    /// Gets the number of arguments needed to successfully format this instance.
    /// </summary>
    public int NumArgumentsNeeded { get; }

    /// <summary>
    ///  Parses a format string and produces a high-quality error string in case of malformed input.
    /// </summary>
    public static bool TryParse([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string? format, [NotNullWhen(true)] out CompositeFormat? compositeFormat, [NotNullWhen(false)] string? error);

API Usage

    if (CompositeFormat.TryParse(formatStringFromConfig, out var cf, out var error);
    {
        if (cf.NumArgumentsNeeded != 0 && cf.NumArgumentsNeeded != 1)
        {
            logger.LogError($"Invalid number of arguments in format string, expecting 0 or 1 arguments but got {cf.NumArgumentsNeeded}");
            return false;
        }
    }
    else
    {
        logger.LogError($"Malformed format string: {error}");
        return false;
    }

    if (cf.NumArgumentsNeeded == 0)
    {
        return string.Format(cf);
    }

    return string.Format(cf, argToFormat);

Alternative Designs

No response

Risks

No response

Author: geeknoid
Assignees: -
Labels:

area-System.Runtime, blocking, api-ready-for-review

Milestone: -

@terrajobst
Copy link
Contributor

  • The conclusion is we want to remove TryParse
  • We'll still expose MinimumArgumentCount
public sealed class CompositeFormat
{
    public static CompositeFormat Parse([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string format);
    public string Format { get; }
    public int MinimumArgumentCount { get; }
}

@terrajobst terrajobst added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation labels Apr 25, 2023
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Apr 25, 2023
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Apr 26, 2023
@ghost ghost locked as resolved and limited conversation to collaborators May 27, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime blocking Marks issues that we want to fast track in order to unblock other important work
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants