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

Proposal: Permit 'value is null' if 'value' is unconstrained generic #1261

Closed
MaStr11 opened this issue Jan 18, 2018 · 4 comments
Closed

Proposal: Permit 'value is null' if 'value' is unconstrained generic #1261

MaStr11 opened this issue Jan 18, 2018 · 4 comments

Comments

@MaStr11
Copy link

MaStr11 commented Jan 18, 2018

Currently the value is null pattern does not compile if value is an unconstrained generic type:

public static void M<T>(T value)
{
    if (value is null) { } //error CS0403: Cannot convert null to type parameter 'T' because it could be a non-nullable value type.
}

This proposal is about removing this restriction.

Motivation

The main benefit would be, that this brings value is null more in line with value == null. Both expressions are almost interchangeable with two exceptions:

  • value == null calls a user-defined equality operator if present, while is null does not.
  • value == null is permitted if value is unconstrained generic, while is null is not allowed.

The second difference can be removed. This would also bring is null more in line with VBs Is Nothing which behaves as == null.

This language change would benefit code fix authors that deal with this kind of expressions and have to special case unconstrained generics (Recent examples are dotnet/roslyn#24237 and dotnet/roslyn#24173). It would also benefit users as it removes an artificial difference between otherwise (almost) identical constructs.

Proposed behavior for value is null

value is null would have to behave as value == null (see also C# spec links below).

Impact / Breaking changes

It is proposed to remove an existing compile time error. So this isn't breaking anything. Existing diagnostic analyzers are affected because CS0403 would no longer be reported (which in turn might cause unit tests to fail).

Some more background

The following snippets show the differences between is null, ==null and VBs Is Nothing in respect to generic type parameter constraints.

public class C {
   //unconstrained
   public bool UnconstrainedIs<T>(T v) =>
       v is null; //error CS0403: Cannot convert null to type parameter 'T' because it could be a non-nullable value type. Consider using 'default(T)' instead.

   public bool UnconstrainedNull<T>(T v) =>
       v == null; // Fine

   //class
   public bool RefconstraintIs<T>(T v) where T:class =>
       v is null; //Fine

   public bool RefconstraintNull<T>(T v)  where T:class =>
       v == null; //Fine
   
   //struct
   public bool ValueconstraintIs<T>(T v) where T:struct =>
       v is null; //error CS0403: Cannot convert null to type parameter 'T' because it could be a non-nullable value type. Consider using 'default(T)' instead.

   public bool ValueconstraintNull<T>(T v)  where T:struct =>
       v == null; //error CS0019: Operator '==' cannot be applied to operands of type 'T' and '<null>'

   public bool ValueconstraintRefEquals<T>(T v)  where T:struct =>
       ReferenceEquals(v, null); // Fine
}

sharplab.io

Public Class C
    Public Sub UnconstrainedIs(Of T)(v As T)
        Dim flag As Boolean = v Is Nothing
    End Sub

    Public Sub RefconstraintIs(Of T As Class)(v As T)
        Dim flag As Boolean = v Is Nothing
    End Sub

    Public Sub ValueconstraintIs(Of T As Structure)(v As T)
        Dim flag As Boolean = v Is Nothing ' error BC30020: 'Is' operator does not accept operands of type 'T'. Operands must be reference or nullable types.
    End Sub

    Public Sub ValueconstraintReferenceEquals(Of T As Structure)(v As T)
        Dim flag As Boolean = ReferenceEquals(v, Nothing)
    End Sub
End Class

shaprlab.io

There is only one case where the three comparisons substantial differ and this proposal is about removing this difference.

C# Spec references

The Reference type equality operators section from the spec about == null

One operand is a value of type T where T is a type_parameter and the other operand is the literal null. Furthermore T does not have the value type constraint.

explicit allows T to be unconstrained. The section The is operator does not mention the is null case. The spec needs to adopt this part from the Reference type equality operators section:

The x == null construct is permitted even though T could represent a value type, and the result is simply defined to be false when T is a value type.

Two more quotes about the difference between user defined comparison:

For an operation of the form x == y or x != y, if any applicable operator == or operator != exists, the operator overload resolution (Binary operator overload resolution) rules will select that operator instead of the predefined reference type equality operator.

Note that user defined conversions, are not considered by the is operator.

Update: Oops! I got that quote wrong. It is about conversions and not comparison.

@MaStr11
Copy link
Author

MaStr11 commented Jan 18, 2018

This change was first proposed by @gafter here.

We should change the language to permit value is null for an unconstrained generic.

I wrote the proposal because I couldn't find something related and I wanted to track this change for dotnet/roslyn#24173.

@zaytsev-victor
Copy link

Related proposal for unconstrained generic #263

@DavidArno
Copy link

DavidArno commented Jan 26, 2018

This idea has now been championed by @gafter in #1284.

Is it appropriate to now close this issue, therefore?

@MaStr11
Copy link
Author

MaStr11 commented Jan 26, 2018

Closed as duplicate of #1284 (Thanks @DavidArno for pointing that out).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants