Replies: 15 comments
-
IIRC the safety that the CLR provides with normal arrays vs. stack-allocated arrays is bounds checking and type-safety. Since However it sounds like what you want is very similar to stack-allocated classes and the problems are largely the same. It's effectively impossible to treat such a reference the same as a heap-allocated reference because you are free to safely do whatever you want with such a reference without worry as to whether or not that reference is still valid. That's not the case with stack-allocated references which are invalid as soon as the allocating method returns. It's impossible to know what a consuming method might do with any given reference, including saving it off to a field for future use. |
Beta Was this translation helpful? Give feedback.
-
Is this proposal different from |
Beta Was this translation helpful? Give feedback.
-
Good call, complete with special syntax to declare/init without requiring Span<int> sp = stackalloc int[100]; |
Beta Was this translation helpful? Give feedback.
-
@HaloFour - To be clear, what I was trying to describe is a stack allocated array that behaves like any value type (struct) with pass-by-value semantics.
@Joe4evr - I'm not sure. I read through the page you linked regarding Span, and it does sound similar. However, it is not clear to me that |
Beta Was this translation helpful? Give feedback.
-
So you're looking for #535? |
Beta Was this translation helpful? Give feedback.
-
Eliminating the heap allocations is the point of that feature. As for the use with |
Beta Was this translation helpful? Give feedback.
-
Thanks for the clarification @HaloFour.
Reading through it, I would say sort of but not entirely. #535 describes various limitations due to the Span being tied directly to the execution stack, like not being able to use it in an async context, etc. What I really want is a value type array that behaves just like any other value type. I updated the title of this thread to reflect that, which hopefully clarifies the ask/proposal. Thanks everyone for sharing your thoughts on this! |
Beta Was this translation helpful? Give feedback.
-
The problem with that idea is that one of the inherent limitations of a value type is that it has a fixed size. The only way to dynamically allocate non-heap space is via |
Beta Was this translation helpful? Give feedback.
-
Is that a problem if the size of the array is fixed and can be determined at compile time? This would always be the case with a value type params array, for example. |
Beta Was this translation helpful? Give feedback.
-
The size would need to be fixed at both the caller and the callee. I don't see what the point would be for having a method accept a |
Beta Was this translation helpful? Give feedback.
-
Yes, requiring the size to be fixed in the callee definition would be pointless :) |
Beta Was this translation helpful? Give feedback.
-
But "any other value type" will happily go to the heap anyway when they're used as/hoisted to a field, such as when captured by a lambda or when it's used between
|
Beta Was this translation helpful? Give feedback.
-
@ryantrem
unsafe struct ValueTypeArray
{
fixed int elem[100];
} Maybe you want a safe version of ValueTypeArray, please have a look at my proposal: #115
class A
{
public int a;
public int[] b;
public A(int a, int[] b)
{
this.a=a;
this.b=b;
}
}
public static A sample = null;
static void function(int a, params int[] b)
{
sample = new A(a, b); //In this case, b can't be allocated on stack!
........
} So, to determine whether to allocate params array on stack, the compiler need to do escape analysis. Please have a look at my proposal: https://github.com/dotnet/coreclr/issues/1784 |
Beta Was this translation helpful? Give feedback.
-
Thanks @Joe4evr for sharing those posts, very enlightening. I'll have to ponder this some! @ygc369 - in the example you provided, I think it would be totally fine for the array to end up on the heap (as mentioned in my original post, perhaps by an implicit conversion from a value type array to a reference type array). I'm not trying to avoid ever having a reference type array, just looking for optimizations for the case where an array is passed to a function and has a short lifetime within the execution stack. Maybe that isn't actually necessary if gen 0 GC is just as fast as releasing the stack frame, but no one has suggested yet that this is the case. :) |
Beta Was this translation helpful? Give feedback.
-
A potential use-case for would be a better implementation of this struct. It's a pretty rare use case, but in this case I needed a super-fast and allocation-free way to track if a large string (>1MB) has changed without needing to store the entire string in memory. public readonly struct LargeStringHash
{
/// hashing constructors here.
void GetLastHash(Span<byte> output)
{
if (output.Length != 16)
{
throw new InvalidOperationException();
}
output[00] = this.byte00;
output[01] = this.byte01;
output[02] = this.byte02;
output[03] = this.byte03;
output[04] = this.byte04;
output[05] = this.byte05;
output[06] = this.byte06;
output[07] = this.byte07;
output[08] = this.byte08;
output[09] = this.byte09;
output[10] = this.byte10;
output[11] = this.byte11;
output[12] = this.byte12;
output[13] = this.byte13;
output[14] = this.byte14;
output[15] = this.byte15;
}
void SetLastHash(ReadOnlySpan<byte> input)
{
if (input.Length != 16)
{
throw new InvalidOperationException();
}
this.byte00 = input[00];
this.byte01 = input[01];
this.byte02 = input[02];
this.byte03 = input[03];
this.byte04 = input[04];
this.byte05 = input[05];
this.byte06 = input[06];
this.byte07 = input[07];
this.byte08 = input[08];
this.byte09 = input[09];
this.byte10 = input[10];
this.byte11 = input[11];
this.byte12 = input[12];
this.byte13 = input[13];
this.byte14 = input[14];
this.byte15 = input[15];
}
byte byte00 = 0;
byte byte01 = 0;
byte byte02 = 0;
byte byte03 = 0;
byte byte04 = 0;
byte byte05 = 0;
byte byte06 = 0;
byte byte07 = 0;
byte byte08 = 0;
byte byte09 = 0;
byte byte10 = 0;
byte byte11 = 0;
byte byte12 = 0;
byte byte13 = 0;
byte byte14 = 0;
byte byte15 = 0;
} |
Beta Was this translation helpful? Give feedback.
-
I'm not sure if this depends on runtime changes or not, so I'll just start here. It would be great if C# supported the concept of stack allocated (value type) arrays in a safe manner. This would be particularly useful in cases where a method takes a variable number of parameters via a params array. If this method is heavily called, it can result in many allocations an GC pressure. Perhaps there would be special syntax for a stack allocated array, such as
stack int[]
, and perhaps there would be implicit conversions between stack allocated arrays and heap allocated arrays.Beta Was this translation helpful? Give feedback.
All reactions