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

Stackalloc array initializers. #1122

Merged
merged 1 commit into from
Jan 22, 2018
Merged

Stackalloc array initializers. #1122

merged 1 commit into from
Jan 22, 2018

Conversation

VSadov
Copy link
Member

@VSadov VSadov commented Nov 20, 2017

In short: Ordinary arrays can be created through the following syntax:

new int[3]
new int[3] { 1, 2, 3 }
new int[] { 1, 2, 3 }
new[] { 1, 2, 3 }

We should allow stack allocated arrays be created through:

stackalloc int[3]				// currently allowed
stackalloc int[3] { 1, 2, 3 }
stackalloc int[] { 1, 2, 3 }
stackalloc[] { 1, 2, 3 }

Ordinary arrays can be created through the following syntax:

```C#
new int[3]
new int[3] { 1, 2, 3 }
new int[] { 1, 2, 3 }
new[] { 1, 2, 3 }
```

We should allow stack allocated arrays be created through:

```C#
stackalloc int[3]				// currently allowed
stackalloc int[3] { 1, 2, 3 }
stackalloc int[] { 1, 2, 3 }
stackalloc[] { 1, 2, 3 }
```
@VSadov
Copy link
Member Author

VSadov commented Nov 20, 2017

@benaadams
Copy link
Member

Skip zero init? Or not be considered for triggering for .locals init to avoid double assign

The semantics of all cases is roughly the same as with arrays.
For example: in the last case the element type is inferred from the initializer and must be an "unmanaged" type.

NOTE: the feature is not dependent on the target being a `Span<T>`. It is just as applicable in `T*` case, so it does not seem reasonable to predicate it on `Span<T>` case.
Copy link
Member

Choose a reason for hiding this comment

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

What are the requirements on the target? Does it work for any type with void*, int length constructor?

(I assume that this is answered in the spec for the currently allowed case without initializer. The link to that spec may be helpful.)

Copy link
Member Author

Choose a reason for hiding this comment

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

It works with any type that has implicit conversion from Span<T>.

Copy link
Member Author

@VSadov VSadov Nov 20, 2017

Choose a reason for hiding this comment

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

From the language semantics stackalloc T[size] expression has Span<T> type, unless it matches backwards-compatible pattern where it must have type T*.

The implementation will call well-known constructor Span<T>(void*, int). Essentially there is one "magic" type - Span<T> and one "magic" method Span<T>(void*, int), that we know about.

Other types opt-in by providing a conversion operator. It is more intentional than matching (void*, int) constructors on random types - who knows what they expect, is that always {ptr, size}, is that size in bytes on elements?
With Span<T> there could be no doubts on {ptr, size} part.

This is also how stackalloc always worked. - you could always participate by having a conversion from T* . Opting in via a conversion is not a new feature.

Copy link
Member

Choose a reason for hiding this comment

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

Essentially there is one "magic" type - Span<T> and one "magic" method Span<T>(void*, int), that we know about.

Ok, that make sense. I was under impression that you are somehow doing this without knowing about magic Span<T> type.

Copy link
Member Author

Choose a reason for hiding this comment

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

We tried avoiding magic types, but arrived to a conclusion that for a robust pattern we would need one type - a generally accepted representation of {ptr, size} tuple.

And then realized, that Span<T> works just fine for that purpose :-)

Copy link
Member

@stephentoub stephentoub Nov 27, 2017

Choose a reason for hiding this comment

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

Since it's based on Span<T>, I assume I'd be able to write:

ReadOnlySpan<char> ros = stackalloc char[] { ch };
...

? Today to do the same thing I need to write:

Span<char> s = stackalloc char[1];
s[0] = ch;
ReadOnlySpan<char> ros = s;
...

Copy link
Member Author

Choose a reason for hiding this comment

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

@stephentoub Yes. That should work.


## Drawbacks
[drawbacks]: #drawbacks

Copy link
Member

Choose a reason for hiding this comment

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

I like how there are no drawbacks :-)

Copy link
Member Author

@VSadov VSadov Nov 20, 2017

Choose a reason for hiding this comment

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

Well, implementing a feature has cost, but it is a kind of obvious drawback. Could not find any other.

@VSadov
Copy link
Member Author

VSadov commented Jan 22, 2018

Merging this, since there are Approvals and no known objections.
Will be discussed in the LDM at the next opportunity.

@VSadov VSadov merged commit 107f795 into dotnet:master Jan 22, 2018
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

Successfully merging this pull request may close these issues.

6 participants