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

Passing null to an method that takes a ReadOnlySpan<T> throws, but default(ReadOnlySpan<int>) does not #23725

Closed
ericstj opened this issue Oct 3, 2017 · 14 comments · Fixed by dotnet/corefx#25257
Assignees
Milestone

Comments

@ericstj
Copy link
Member

ericstj commented Oct 3, 2017

This is because default(ReadOnlySpan) results in a zero-length span, null is treated as a T[] which is implicitly converted to ReadOnlySpan and triggers a null check in the constructor.

It's non-intuitive for an implicit operator to throw. It violates the API design guidelines as well:

X DO NOT throw exceptions from implicit casts.
It is very difficult for end users to understand what is happening, because they might not be aware that a conversion is taking place.

/cc @ahsonkhan @KrzysztofCwalina

@ahsonkhan
Copy link
Contributor

Should the implicit operation call an internal constructor which returns default(Span) when the array is null instead of throwing?
https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/Span.cs#L351

The implicit cast would also throw if there is an array mismatch. What should we do in that scenario?

static void Main(string[] args)
{
    string[] a = { "Hello" };
    ReadSpanLength(a);  // Throws System.ArrayTypeMismatchException: Attempted to access an element as a type incompatible with the array.
}

public static void ReadSpanLength(Span<object> span)
{
    Console.WriteLine(span.Length);
}

@KrzysztofCwalina
Copy link
Member

Yeah, I think this is reasonable, i.e. the cast should result in empty memory

@ahsonkhan
Copy link
Contributor

The implicit cast would also throw if there is an array mismatch. What should we do in that scenario?

Yeah, I think this is reasonable, i.e. the cast should result in empty memory

Even for array type mismatch?

@KrzysztofCwalina
Copy link
Member

I would not change the ctor; just the cast operator. In the cast operator, there is no possibility of mismatch (as the type of the span is inferred from the array), is there?

@ahsonkhan
Copy link
Contributor

ahsonkhan commented Oct 4, 2017

there is no possibility of mismatch

What about array covariance (from the code snippet I posted above)?

object[] array = new String[10];

cc @jkotas

@KrzysztofCwalina
Copy link
Member

KrzysztofCwalina commented Oct 4, 2017

keep going, i.e. how do I get to be casing null?

@ahsonkhan
Copy link
Contributor

keep going, i.e. how do I get to be casing null?

In the code snippet, there is no null casting, but it still goes against the guideline that @ericstj mentioned since an implicit cast (from string[] to Span<object>) is resulting in an exception being thrown.

@benaadams
Copy link
Member

Similar issue to https://github.com/dotnet/coreclr/issues/14012 on ArraySegments

@KrzysztofCwalina
Copy link
Member

I think casting nulls, comparing nulls, etc. should just work and we can make it work. I don't believe there is a solution to the covarinace issue, i.e.

object[] array = new String[10];
Span<object> s = array;

will always fail and we cannot make it not fail.

@ericstj
Copy link
Member Author

ericstj commented Oct 5, 2017

What if you delayed the co-variance exception to access instead of in the constructor? Do you think it would be a more intuitive failure, or do you think this is a case where we have to break the rule (you wrote I believe 😉) about throwing from implicit cast.

@KrzysztofCwalina
Copy link
Member

I think we need to break the rule.
Doing the check in the accessors (e.g. the indexer) would be both slow and probably surprising

@benaadams
Copy link
Member

benaadams commented Oct 5, 2017

Its the Exception that proves the rule 😉 (assuming that translates and is not just a nonsensical British phrase)

@KrzysztofCwalina
Copy link
Member

That would be an awsome annotation to the design guideline :-)

@ericstj
Copy link
Member Author

ericstj commented Oct 17, 2017

I do think we need some guidelines for Span/Memory as well.

@ahsonkhan ahsonkhan self-assigned this Nov 15, 2017
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.1.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 20, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants