Modeling a lifetime really comes down to answering two questions:
- What are the lifetime defaults for a scenario? Defaults when possible should lean into how the majority of developers are going to expect the code to work. The ideal outcome being that developers never realize lifetimes are even at play here.
- How does a developer invert a default when it does not work for their scenario?
For collection literals I believe we should embrace the following rules:
When a collection literal is used to initialize a
ref struct
local the value should not be returnable
The rationale being that developers using a ref struct
which represents a collection is doing so for performance reasons. The compiler
should lean into that by optimizing these scenarios as much as possible including leveraging stack allocation. This is the more natural
interpretation of developers intent. If developers wanted to use a collection which was returnable then they would use a traditional
collection type.
Span<int> M() {
Span<int> span = [1, 2, 3];
// Illegal
return span;
}
In order to invert the default here developers can express their intent by using a traditional collection type
Span<int> M() {
int[] array = [1, 2, 3];
return array.AsSpan();
}
When a collection literal is used as a method argument the value should not be returnable from the current method of the following are true
- The parameter type is a
ref struct
and the parameter isscoped
- The parameter type is a
ref struct
and there are noref struct
return orref / out / in
parameters
For parameters intent is declared by the author of the method and that only comes from the scoped
modifier. If that modifier is
not present and the value has a path to be returned then the compiler must respect that and create a value that is returnable.
Otherwise the compiler can opmtimize it.
For situations where this decision does not work the developer can include an explicit cast to force the collection literal to be
unoptimized. For example G((int[])[1, 2, 3])
.
In all other cases the compiler should emit expressions that have ref safe to escape of calling method (returnabel values).
Note: a future expansion of collection literals could consider allowing new
to appear before a literal as a method of indicating "do not optimize this".