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

Ensure the generic math interfaces are implemented implicitly where possible #66748

Merged
merged 5 commits into from
Mar 17, 2022

Conversation

tannergooding
Copy link
Member

@tannergooding tannergooding commented Mar 17, 2022

Notably this deviates from API review slightly. In API review, it was determined that interfaces should be implicitly implemented. However, most types cannot implement the operators implicitly. This comes down to causing issues with System.Linq.Expressions for a couple types and it being a technically problematic scenario from the perspective of the C# Language Spec (but not the current Roslyn implementation). Likewise, IntPtr and UIntPtr have a pending design discussion with relevant folks from the C# Language Design Team to determine what the penultimate behavior is going to be.

The meeting around IntPtr/UIntPtr is going to happen before the next API review and the deviation here is going to be raised in the next API review. It shouldn't be considered a blocker, however.

@ghost ghost assigned tannergooding Mar 17, 2022
@dotnet-issue-labeler
Copy link

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

Comment on lines +1078 to 1079
/// <inheritdoc cref="IAdditiveIdentity{TSelf, TResult}.AdditiveIdentity" />
static char IAdditiveIdentity<char, char>.AdditiveIdentity => (char)0;
Copy link
Member Author

Choose a reason for hiding this comment

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

API review will need to discuss if exposing AdditiveIdentity, MultiplicativeIdentity, One, and Zero make sense for char. They are not exposed until that discussion happens.

All of the operators exist in regular C#, but unlike the other types the members being exposed publicly may be potentially confusing or "incorrect" terminology for char.

[MethodImpl(MethodImplOptions.AggressiveInlining)]
static char INumber<char>.Create<TOther>(TOther value)
public static char Create<TOther>(TOther value)
Copy link
Member Author

Choose a reason for hiding this comment

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

The Create APIs are still pending being extracted to IConvertible interfaces as per API review (dotnet/designs#205 (comment))

This will occur in a follow up PR. This PR is just making the incremental steps of taking the preview surface and exposing it publicly for simplicity

public const decimal MultiplicativeIdentity = 1m;

/// <inheritdoc cref="ISignedNumber{TSelf}.NegativeOne" />
public const decimal NegativeOne = -1m;
Copy link
Member Author

Choose a reason for hiding this comment

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

Decimal already defines and exposes MinusOne. This will need to be discussed in API review.

My own preference is MinusOne is the "incorrect" name and we shouldn't propagate it to the other types or interfaces.

static decimal INumber<decimal>.Sign(decimal value)
=> Math.Sign(value);
/// <inheritdoc cref="INumber{TSelf}.Sign(TSelf)" />
static decimal INumber<decimal>.Sign(decimal value) => Math.Sign(value);
Copy link
Member Author

Choose a reason for hiding this comment

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

decimal already exposes int Sign(decimal). We'll want to discuss in API review whether or not normalizing Sign(T) as being special and always returning int is desirable and how to reconcile the exposed API surface otherwise.

static byte System.IMultiplicativeIdentity<System.Byte,System.Byte>.MultiplicativeIdentity { get { throw null; } }
static byte System.INumber<System.Byte>.One { get { throw null; } }
static byte System.INumber<System.Byte>.Zero { get { throw null; } }
public static System.Byte Abs(System.Byte value) { throw null; }
Copy link
Member Author

Choose a reason for hiding this comment

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

Just noting that GenerateReferenceSource isn't consistent in when it picks System.Byte vs byte. It should likely prefer the latter since that's the default we use in source and is unambiguous.

Copy link
Member Author

Choose a reason for hiding this comment

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

Likewise noting that GenerateReferenceSource doesn't like static abstracts in interfaces today. It doesn't include the relevant accessibility modifier (such as public) and it treats operators as their IL name, rather than their C# syntax (e.g. op_Addition rather than operator +).

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for commenting on these. Please accumulate all of the GenerateReferenceSource issues you're encountering and log an issue in dotnet/arcade.
(some existing issues for reference)

@@ -3588,6 +3302,13 @@ public sealed partial class InsufficientMemoryException : System.OutOfMemoryExce
public static System.IntPtr MaxValue { get { throw null; } }
public static System.IntPtr MinValue { get { throw null; } }
public static int Size { get { throw null; } }
static nint System.IAdditiveIdentity<nint,nint>.AdditiveIdentity { get { throw null; } }
Copy link
Member Author

Choose a reason for hiding this comment

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

Noting that GenerateReferenceSource is not nint vs IntPtr aware and will not pick the appropriate of the type vs the keyword based on what's in source.

It happens to error in most of the right places if they don't line up due to the difference in attributes, however. It would just be nice if the task generated the right source from the start.

@ghost
Copy link

ghost commented Mar 17, 2022

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

Issue Details

Notably this deviates from API review slightly. In API review, it was determined that interfaces should be implicitly implemented. However, most types cannot implement the operators implicitly. This comes down to causing issues with System.Linq.Expressions for a couple types and it being a technically problematic scenario from the perspective of the C# Language Spec (but not the current Roslyn implementation). Likewise, IntPtr and UIntPtr have a pending design discussion with relevant folks from the C# Language Design Team to determine what the penultimate behavior is going to be.

The meeting around IntPtr/UIntPtr is going to happen before the next API review and the deviation here is going to be raised in the next API review. It shouldn't be considered a blocker, however.

Author: tannergooding
Assignees: tannergooding
Labels:

area-System.Runtime, new-api-needs-documentation

Milestone: -

@tannergooding
Copy link
Member Author

CC. @jeffhandley

@stephentoub
Copy link
Member

Likewise, IntPtr and UIntPtr have a pending design discussion with relevant folks from the C# Language Design Team to determine what the penultimate behavior is going to be.

penultimate? What comes after that design decision?

@tannergooding
Copy link
Member Author

penultimate? What comes after that design decision?

The upcoming meeting will make the decision on whether IntPtr/UIntPtr has the interface members implicitly or explicitly implemented or if some other modification will exist here. It will decide whether LeadingZeroCount (and other APIs) are legal to invoke off nint and/or IntPtr or neither (only being valid in a generic context on a properly constrained T).

@stephentoub
Copy link
Member

Right, I'm confused by the penultimate (i.e. next to last) part. There's another IntPtr/UIntPtr decision after that?

@tannergooding
Copy link
Member Author

Right, I'm confused by the penultimate (i.e. next to last) part. There's another IntPtr/UIntPtr decision after that?

The decision reached by the C# team and the relevant API review members present will need to be reiterated as part of the API review that occurs after (currently scheduled the next Tuesday after). It likely won't influence IntPtr/UIntPtr any further than that, but may influence our decisions around other APIs and how they're exposed.

@stephentoub
Copy link
Member

stephentoub commented Mar 17, 2022

The decision reached by the C# team and the relevant API review members present will need to be reiterated as part of the API review that occurs after (currently scheduled the next Tuesday after). It likely won't influence IntPtr/UIntPtr any further than that, but may influence our decisions around other APIs and how they're exposed.

Ok, got it, good. I was worried there was some big lurking thing beyond I wasn't aware of :)

Copy link
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

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

I skimmed the changes. Other than fixing the ODBC build and fixing the comments on the consts, LGTM.

@jeffhandley jeffhandley requested a review from dakersnar March 17, 2022 03:11
Copy link
Member

@jeffhandley jeffhandley left a comment

Choose a reason for hiding this comment

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

I reviewed all of the changes at ~65% thoroughness. It seems pretty mechanical, @tannergooding. Other than the places where you left comments, the APIs that are still blocked by language features, and the <inheritdoc> feedback, is there anything else you'd like particular attention on?

// static checked byte IAdditionOperators<byte, byte, byte>.operator +(byte left, byte right)
// => checked((byte)(left + right));
// /// <inheritdoc cref="IAdditionOperators{TSelf, TOther, TResult}.op_CheckedAddition(TSelf, TOther)" />
// static byte IAdditionOperators<byte, byte, byte>.operator checked +(byte left, byte right) => checked((byte)(left + right));
Copy link
Member

Choose a reason for hiding this comment

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

Note to other reviewers:
The checked operators are blocked by [Proposal]: Checked Operators · Issue #4665 · dotnet/csharplang

Comment on lines +739 to +740
// /// <inheritdoc cref="IFloatingPoint{TSelf}.Exp10(TSelf)" />
// public static double Exp10(double x) => Math.Exp10(x);
Copy link
Member

Choose a reason for hiding this comment

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

Please remind me while all of these are still commented out? What are these APIs blocked on?

Copy link
Member Author

Choose a reason for hiding this comment

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

These are APIs that are approved but not implemented on System.Math or System.MathF

Ideally we get them also implemented and exposed for .NET 7, but the "worst case" is they become DIMs in .NET vNext

// static sbyte IShiftOperators<sbyte, sbyte>.operator >>>(sbyte value, int shiftAmount)
// => (sbyte)((byte)value >> shiftAmount);
// /// <inheritdoc cref="IShiftOperators{TSelf, TResult}.op_UnsignedRightShift(TSelf, int)" />
// static sbyte IShiftOperators<sbyte, sbyte>.operator >>>(sbyte value, int shiftAmount) => (sbyte)((byte)value >> shiftAmount);
Copy link
Member

Choose a reason for hiding this comment

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

@dakersnar
Copy link
Contributor

Thanks for looping me in on this. I skimmed the changes, as well as the reviewer comments. I agree with @jeffhandley that this seems mostly mechanical. LGTM at a high level.

radekdoulik pushed a commit to radekdoulik/runtime that referenced this pull request Mar 30, 2022
…ossible (dotnet#66748)

* Updating generic math interfaces to be implicitly implemented where possible

* Resolve a build error in OdbcConnection caused by new Parse APIs

* Revert "Resolve a build error in OdbcConnection caused by new Parse APIs"

This reverts commit 6fd7ec7.

* Suppress CA1846 for System.Data.Odbc

* Updating the xml doc comments for exposed constants
@ghost ghost locked as resolved and limited conversation to collaborators Apr 21, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants