-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Edited by @terrajobst. Original request at the end. The spec for this feature is here.
Background and motivation
In .NET 6, we've added a way to ship preview features in otherwise stable releases. It works by tagging APIs (and language features) as preview features and requiring the user's project to explicitly opt-into using them via the <EnablePreviewFeatures> property.
The feature was primarily designed to accommodate platform-level preview features, that is for features that span runtime, library, and language, such as generic math. However, we also believed that the feature would work for libraries that want to offer preview functionality in otherwise stable NuGet packages.
This feature is about providing a model that works great for library authors. For details, see the design document.
API Proposal
namespace System.Diagnostics.CodeAnalysis;
[AttributeUsage(AttributeTargets.Assembly |
AttributeTargets.Module |
AttributeTargets.Class |
AttributeTargets.Struct |
AttributeTargets.Enum |
AttributeTargets.Constructor |
AttributeTargets.Method |
AttributeTargets.Property |
AttributeTargets.Field |
AttributeTargets.Event |
AttributeTargets.Interface |
AttributeTargets.Delegate, Inherited = false)]
public sealed class ExperimentalAttribute : Attribute
{
public ExperimentalAttribute(string diagnosticId);
public string DiagnosticId { get; }
public string? UrlFormat { get; set; }
}API Usage
Shipping an experimental API in a stable package
Martin builds a library that integrates with ASP.NET Core and provides features to make it easier to build services. The library is distributed as a NuGet package. The package is already in a version well past 1.0 and is considered stable.
He ships the package often and doesn't want to maintain multiple flavors of the package, one marked as prerelease and one marked as stable. However, he wants to expose new APIs without making the promise that these APIs are stable. He designs the new APIs as if they would be stable, that is, he puts them in the namespace they belong and names the types and members without any naming convention that implies that they aren't stable yet. If customer feedback is positive, the API will become stable as-is, otherwise he'll make changes to address the feedback.
In order to convey to the consumers that these APIs aren't stable yet, he puts the Experimental attribute on them:
namespace MartinsLibrary.FancyLogging
{
public static class FancyLoggerExtensions
{
[Experimental("ML123", UrlFormat="https://martinslibrary.net/diagnostics/{0}")]
public static IServiceCollection AddFancyLogging(this IServiceCollections services)
{
// ...
}
}
}Consuming an experimental API
David builds a new version of Jabber.NET and consumes Martin's library. He very much wants to play with the new fancy logging Martin added. When David calls AddFancyLogging he gets a compilation error:
error ML123: FancyLoggerExtensions.AddFancyLogging() is not a stable API. In order to consume this experimental API, suppress this error from the call site.
David is happy to accommodate future breaking changes around the fancy logging feature. He understands that the diagnostic ID is specific to the fancy logging feature of Martin's library, so he decides to add a suppression to the project file:
<Project>
<PropertyGroup>
<!-- Fancy logging is an experimental APIs -->
<NoWarn>$(NoWarn);ML123</NoWarn>
</PropertyGroup>
</Project>Original Request
### Background and motivationLibrary developers often want to experiment with APIs before committing to long-term support. This is true within an organization, as well as within the open-source community. It would be very useful for the .NET infrastructure to support experimental interfaces in a first class way.
The idea is to flag the use of experimental APIs in calling code, to make developers aware that they're calling into an API which is not yet settled and is subject to change outside of the normal support model for the component.
The attribute would be supplemented by a Roslyn analyzer that reports use of experimental APIs. You can also imagine special treatment in IntelliSense and in DocFx for experimental APIs.
API Proposal
namespace System.Diagnostics.CodeAnalysis;
/// <summary>
/// Indicates that an API element is experimental and subject to change without notice.
/// </summary>
[AttributeUsage(
AttributeTargets.Class |
AttributeTargets.Struct |
AttributeTargets.Enum |
AttributeTargets.Interface |
AttributeTargets.Delegate |
AttributeTargets.Method |
AttributeTargets.Constructor |
AttributeTargets.Property |
AttributeTargets.Field |
AttributeTargets.Event |
AttributeTargets.Assembly)]
public sealed class ExperimentalAttribute : Attribute
{
/// <summary>
/// Gets a human readable explanation for marking API as experimental.
/// </summary>
public string? Message { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ExperimentalAttribute"/> class.
/// </summary>
public ExperimentalAttribute()
{
// Intentionally left empty.
}
/// <summary>
/// Initializes a new instance of the <see cref="ExperimentalAttribute"/> class.
/// </summary>
/// <param name="message">Human readable explanation for marking experimental API.</param>
public ExperimentalAttribute(string message)
{
Message = Throws.IfNull(message);
}
}API Usage
[Experimental("Trying this out, maybe committed in the 3.1 release")]
public void DoSomethingNew();
[assembly: Experimental("This whole assembly is subject to change without notice")]Alternative Designs
No response
Risks
No response