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

Warn when comparing spans to null #84265

Closed
terrajobst opened this issue Apr 3, 2023 · 6 comments · Fixed by dotnet/roslyn-analyzers#6838
Closed

Warn when comparing spans to null #84265

terrajobst opened this issue Apr 3, 2023 · 6 comments · Fixed by dotnet/roslyn-analyzers#6838
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime code-analyzer Marks an issue that suggests a Roslyn analyzer
Milestone

Comments

@terrajobst
Copy link
Member

terrajobst commented Apr 3, 2023

The following code

var array = new char[0];
var span = array.AsSpan();
var emptyArray = Array.Empty<char>();
var emptySpan = Span<char>.Empty;

if (array == null)
    Console.WriteLine("array is null");
else
    Console.WriteLine("array is not null");

if (span == null)
    Console.WriteLine("span is null");
else
    Console.WriteLine("span is not null");

if (emptyArray == null)
    Console.WriteLine("emptyArray is null");
else
    Console.WriteLine("emptyArray is not null");

if (emptySpan == null)
    Console.WriteLine("emptySpan is null");
else
    Console.WriteLine("emptySpan is not null");

outputs the following:

array is not null
span is not null
emptyArray is not null
emptySpan is null

The only surprising one is Span<char>.Empty == null resulting in true.

Spans can be compared to null because there is an implicit conversion from arrays to spans and the null literal can be converted to an array, so the compiler ends up emitting this:

if (Span<char>.op_Equals(emptySpan, (Span<char>)((char[])null)))
    Console.WriteLine("emptySpan is null");
else
    Console.WriteLine("emptySpan is not null");

The empty span is defined as the null literal converted to a span, so this resulting in true is, albeit surprising, sensible and by design.

This effectively hides the built-in diagnostic CS8073 against comparing value types to null. We should consider adding a diagnostic for comparisons between spans and null.

As pointed out, this should probably also result in a warning:

Span<Cell> line = null;

More context on Twitter.

@terrajobst terrajobst added api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime code-analyzer Marks an issue that suggests a Roslyn analyzer labels Apr 3, 2023
@ghost
Copy link

ghost commented Apr 3, 2023

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

Issue Details

The following code

var array = new char[0];
var span = array.AsSpan();
var emptyArray = Array.Empty<char>();
var emptySpan = Span<char>.Empty;

if (array == null)
    Console.WriteLine("array is null");
else
    Console.WriteLine("array is not null");

if (span == null)
    Console.WriteLine("span is null");
else
    Console.WriteLine("span is not null");

if (emptyArray == null)
    Console.WriteLine("emptyArray is null");
else
    Console.WriteLine("emptyArray is not null");

if (emptySpan == null)
    Console.WriteLine("emptySpan is null");
else
    Console.WriteLine("emptySpan is not null");

outputs the following:

array is not null
span is not null
emptyArray is not null
emptySpan is null

The only surprising one is Span<char>.Empty == null resulting in true.

Spans can be compared to null because there is an implicit conversion from arrays to spans and the null literal can be converted to an array, so the compiler ends up emitting this:

if (Span<char>.op_Equals(emptySpan, (Span<char>)((char[])null)))
    Console.WriteLine("emptySpan is null");
else
    Console.WriteLine("emptySpan is not null");

The empty span is defined as the null literal converted to a span, so this resulting in true is, albeit surprising, sensible and by design.

This effectively hides the built-in diagnostic CS8073 against comparing value types to null. We should consider adding a diagnostic for comparisons between spans and null.

More context on Twitter.

Author: terrajobst
Assignees: -
Labels:

api-suggestion, area-System.Runtime, code-analyzer

Milestone: -

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Apr 3, 2023
@EgorBo
Copy link
Member

EgorBo commented Apr 3, 2023

#76735, I thought the plan was to add MemoryExtensions.ReferenceEqual and mark Span.Equals as obsolete/hide from intelisense?

@MichaelRumpler
Copy link

Maybe also a warning if you set a Span<T> to null? Because this is also possible:

Span<Cell> line = null;

This is one more reason that users could think Span is an object and therefore also the comparison is ok.

@terrajobst
Copy link
Member Author

terrajobst commented Apr 5, 2023

@EgorBo

#76735, I thought the plan was to add MemoryExtensions.ReferenceEqual and mark Span.Equals as obsolete/hide from intelisense?

Looks like that got closed in favor of #54794. I'm not sure whether this issue is now a dupe or related.

@GrabYourPitchforks?

@MichaelRumpler

Maybe also a warning if you set a Span<T> to null?

Good point!

@tannergooding tannergooding added api-ready-for-review API is ready for review, it is NOT ready for implementation 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 labels May 26, 2023
@terrajobst
Copy link
Member Author

terrajobst commented Jul 18, 2023

Video

We should warn for any comparison against spans and memories (==, !=, is, is not):

  • Comparisons against the default span should be written as span.IsDefault. Which doesn't exist but we could add one.
  • Comparisons against content should be done as span.SequenceEqual(...)
  • Comparisons against null don't make sense

It seems we don't have consensus on this view point. We should discuss this with once we have quorum again.

@terrajobst terrajobst added api-needs-work API needs work before it is approved, it is NOT ready for implementation api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-ready-for-review API is ready for review, it is NOT ready for implementation api-needs-work API needs work before it is approved, it is NOT ready for implementation labels Jul 18, 2023
@terrajobst
Copy link
Member Author

terrajobst commented Jul 25, 2023

Video

We should warn for any comparison against spans and memories involving the null literal (== null, != null, is null, is not null). If someone writes == default then they likely meant the default span, which is meaningful and should be allowed.

  • Comparisons against the default span should be written as == default.
  • Asking whether the span is empty should be written as span.IsEmpty

Category: Usage
Severity: Warning

@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 Jul 25, 2023
@ericstj ericstj added the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Aug 14, 2023
@ericstj ericstj added this to the Future milestone Aug 14, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Apr 4, 2024
@tannergooding tannergooding removed the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Jun 24, 2024
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 code-analyzer Marks an issue that suggests a Roslyn analyzer
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants