Proposal: add interface support to ref structures such as Span and ReadOnlySpan #1833
Replies: 34 comments
-
@AlexRadch This contravenes the design of Conclusion: there's no way to make ref structs implement an interface withouth major overhaul of the CLR type system. |
Beta Was this translation helpful? Give feedback.
-
@popcatalin81 I do not sagest to overhaul of the CLR type system. I think it will be possible to add some separated stacked heap for such interfaces, classes a structures that are allocated on stack only. Stack allocated instances (interface, class or structure) can not be used to call any method. Only to call methods that support stack allocated instances. And such methods will not store stack allocated instances on heap. That will be checked by dotNet at compiler time. Conclusion: I think there is way to make ref structs implement an interfaces that are allocated only on stack.
See dotnet/corefxlab#2463 for more |
Beta Was this translation helpful? Give feedback.
-
That's precisely the part which requires CLR type system overhaul. |
Beta Was this translation helpful? Give feedback.
-
I do not think so. I think it is like adding to CLR type system "ref struct" support. It will require some small extension of CLR type system but will not overhaul it because usual heap objects will not use any stack allocated instance so there are no any changes in that part. Inside some methods with special syntax will be added support of stack allocated instances. But it is not more than to add "ref struct" support. Such support was added for "ref struct" and it can be added for "stack allocated instance" or "stack allocated interface" because they will have special syntax and compiled with such support. |
Beta Was this translation helpful? Give feedback.
-
No CLR changes were required to support The first rule is that these types can never end up on the heap. Allowing them to implement interfaces and allowing them to be passed to methods that expect references to those interfaces immediately and completely violates that rule. Even if you could somehow get the CLR to allow interface references to exist on the heap by treating those types as just interfaces you lose all of the remaining safe guards which exist to prevent the It makes zero sense to add this support to the language or to the CLR. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour |
Beta Was this translation helpful? Give feedback.
-
I think that my proposal is based on next proposal dotnet/roslyn#16154 |
Beta Was this translation helpful? Give feedback.
-
How do you know how much stack space you need to allocate for an |
Beta Was this translation helpful? Give feedback.
-
On stack it is stored only as reference. All other part are stored on heap, but with big difference. Compiler will disable any reference on it from any other heap instances. Only from other stack instances. Compiler will check that stacked instances are created and destroyed in correct order. Last created is first destroyed (LIFO order). Early created instance can not get reference to later created, but later created instances can reference to early created. There are no circle references for stacked instances. So when reference removed from stack, compiler will destroy instance on heap without reference counting. |
Beta Was this translation helpful? Give feedback.
-
So it's not actually allocated on the stack, therefore it has nothing to do with |
Beta Was this translation helpful? Give feedback.
-
Now c# does not support it but my proposal is to add support for stack allocated instances (for classes, interfaces and structures) and enable references between them. Such references will have special rules. So it will be possible to store reference from stack allocated instance to ref structure. |
Beta Was this translation helpful? Give feedback.
-
You're contradicting yourself. Either they are allocated on the stack, and suffer inherent limitations, or they are not, in which case this proposal cannot be linked to |
Beta Was this translation helpful? Give feedback.
-
Usual instances can not have reference to ref struct only because compiler can not guarantee that object will be destroyed before ref struct. For stacked instancies compiler will guarantee that. So compiler can enable references or including ref struct inside stacked instancies. |
Beta Was this translation helpful? Give feedback.
-
But then it's still not allocated on the stack, so that defeats the entire purpose. What's your actual use-case? It sounds more like you want an object with a controlled lifetime, not a stack-allocated value type with interfaces, because your proposal will mean they're no longer stack-allocated... |
Beta Was this translation helpful? Give feedback.
-
Care to explain how would the C# compiler do that? What you want is technically doable. But it's rather complicated, it involves runtime support and may not be very usable as it kind of forks the type system. This "add some separated stacked heap" is just contraption, not an actual solution to this problem. |
Beta Was this translation helpful? Give feedback.
-
Indeed, a lot of people in csharplang seem far too wiling to comment on stuff they're not familiar with. |
Beta Was this translation helpful? Give feedback.
-
Which is it? I've yet to see anyone successfully manage to create a reference type on the stack. No managed languages that I know of support this, including C++/CLI. That leads me to believe that it's not possible without CLR changes. Those changes very well may be minimal, code wise, but that's still a pretty big paradigmatic shift if the CLR will allow for non GC-managed reference types. And in the end it still doesn't solve the problem of allowing
Fine, illuminate us as to what the CLR is actually capable of doing. I'd love to learn something new about the CLR. I'd be just as interested to hear that it's not possible but that the CLR team is actually considering making these changes. |
Beta Was this translation helpful? Give feedback.
-
Simple: ref struct StackBox<T>
{
public IntPtr objhdr;
public IntPtr mt;
public T value;
}
StackBox<int> sbi = default;
sbi.mt = typeof(int).TypeHandle.Value;
sbi.value = 42;
IntPtr objref = (IntPtr)(&sbi.mt);
object obj = Unsafe.As<IntPtr, object>(ref objref);
Console.WriteLine(obj.GetType()); // prints System.Int32 Sure, it doesn't work with spans because you can't use span as a generic type argument. You could create a dedicated
Not really. As already mentioned, the GC/JIT may need some patches to not blindly assume that any reference type object is in the GC heap. But it's not "big paradigmatic shift". Java already does this and it's not even visible to the developer.
Sure it does. The method table you put in the stack box doesn't have to be Span's method table, it can be the method table of another type that has the same layout as span and implements the interfaces. The big question here is if you can actually implement all the required interfaces/members. But
Yes, I already stated that this is the actual issue. There's probably a reasonable good chance to not require runtime support for this, as long as you don't care about verifiable IL. It may be as simple as adding And then there's the question if it's feasible to expect frameworks to start adding such attributes. In general, there are many things that could be problematic, worth discussing, turn out to be not feasible/worthwhile etc. But storing reference types on the stack or having span implement interfaces are minor details. |
Beta Was this translation helpful? Give feedback.
-
@mikedn you can put an object header anywhere you want, copy a type handle value to it and have a fake CLR object in a snap. You could put in in unmanaged memory or even in the middle of a string if you want to. That does not make the object a safe CLR value which is Type safe and GC friendly. |
Beta Was this translation helpful? Give feedback.
-
Hacking your own box structure? That is pretty neat. Seems a bit excessive. I was hoping that there was some weird tricky to cause the allocation of a reference type (
IMO the expectation is a big paradigmatic shift. What Java does is an implementation detail of hot spot strictly for the purposes of optimization. To my knowledge there's no Java byte code that you can write to request that it happen. And the CLR team doesn't seem to think that stack allocation based on escape analysis is worth the effort. |
Beta Was this translation helpful? Give feedback.
-
Can you please point me to where I stated that this is safe to do in the current implementation. Or can you point me to whatever analysis have you done to prove that this is indeed unsafe and probably difficult to make safe? If not, then I suggest you drop the attitude. Sadly, reading a thousand page book doesn't make people experts. Just saying. |
Beta Was this translation helpful? Give feedback.
-
It's no different from what the runtime does when creating an object. In general, the problem is not creating the necessary memory layout. The problem is where you put it, having a value on the stack being reachable through a normal object reference might cause some GC problems. But it's not fundamentally impossible.
Sure, it happens so that Java doesn't have value types so it can't really create the necessary memory layout on the stack without runtime support. If .NET happens to be in a better position to do that at IL level then good for it.
Could be. That's up for them to decide. I suspect that might be OK if this was some groundbreaking feature. But it doesn't seem to be, Span was added for efficiency reasons and accessing a span via an interface isn't exactly efficient.
The ball is mostly in the JIT team's yard. A prototype was done but it's probably still a long way to production and the JIT team has its hands full. And it's quite possible that JIT based escape analysis isn't indeed worth the effort due to the high cost and/or inherent limitations the JIT has. On the other hand, an offline IL optimizer might be able to do it, provided that a hack lack |
Beta Was this translation helpful? Give feedback.
-
@mikedn Why I can not use |
Beta Was this translation helpful? Give feedback.
-
@AlexRadch Use the Nuget Package https://www.nuget.org/packages/System.Runtime.CompilerServices.Unsafe/ |
Beta Was this translation helpful? Give feedback.
-
How can I pin ref T? |
Beta Was this translation helpful? Give feedback.
-
Hmm? Why would you want to do that? How is that related to this issue? |
Beta Was this translation helpful? Give feedback.
-
Fyi, work has started on stack-allocated objects. dotnet/coreclr#20251 |
Beta Was this translation helpful? Give feedback.
-
@jnm2 Thanks. I don't think that work will allow ref struct to implement interfaces. However, it might eliminate the need for it, at least partially. |
Beta Was this translation helpful? Give feedback.
-
See #2975 for a proposal discussing how to make this work. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Proposal: add interface support to ref structures such as Span and ReadOnlySpan. See dotnet/corefxlab#2463
Beta Was this translation helpful? Give feedback.
All reactions