Boxing
Can someone help me understand boxing?
I'm struggling to understand why using IFoo<T> where T: struct, IFoo<T> would be an advantage over using T directly, but If I make an IFoo it gets boxed
Is there some way to prevent boxing while still using multiple types of IFoo<T>?
33 Replies
I don't know what your example means
Do you know the difference between a reference type and a value type, or a class and a struct?
More or less, what I want to do is implement a class that works with both a generic and non-generic interface and a property that implements another generic interface, but still avoid boxing of the struct.
There's no difference for classes, just use the interface if you can. It's gonna compile to basically the same code
For structs, you need to pass a concrete implementation to a method with a generic so the jit can recompile the method
if you just accept an interface, it's going to box, always
Yeah I'm looking to do this with structs though, which preferably I'd keep, but it seems there's no way to abstract away the generic T, apart from writing a factory method, I suppose
let me understand
From what I've read it seems an IFoo<T> will still be kept unboxed, is that not correct?
is your
IFoo
something like object Deserialize(string);
? and you generic IFoo is like T Deserialize(string)
?
no
you need to accept a T
interfaces are always reference types
you accept a T that implements an interface
which you indicate in the constraint
that's fine
using methods from IFoo via a T is fineRight yeah okay, I got it
but the second you convert it to an IFoo, it's going to get boxed
nothing you can do about it
Right, I think I get it, thanks.
np
it would make sense honestly but I don't think that's how it works
you should check it with sharp lab
to confirm
means I can still write a factory method that returns an IBar which in turn implements a specific IFoo<something>
Bit of a roundabout way to do it but it should work
Well for my specific case I now have an IVector<T> where T: struct, IVector<T>
Which should keep the IVector<Foo> unboxed.
It would make sense, but I don't think it will
if you pass it as
IVector<T>
or the method gets inlinedYeah but I'm passing T directly, so it should be fine,
As in, the next class up in the hierarchy is
show the method signature where you pass it the vector
So basically just using it as a constraint. I think I can include a factory method that instantiates this with the proper implementation of the interface.
It's a bit of a roundabout way to do it but this allows me to use the built in optimised Vector2 and Vector3 while still allowing my own less optimised VectorN for higher dimensions
Should save on performance in the end
or maybe the whole method
ok
system.numerics? aren't those for simd specifically?
yes, I think they should be faster and if they're not it's easy enough to swap them out for another implementation
All I know about SIMD is that it's supposed to be better when parallel processing large datasets which is what I'll end up doing lol
To give you another way to think about it, the method needs to know the size of the variable being passed in. If it knows there's a T, then it can be specialized for every T. If it just knows there's an IFoo, then it isn't specialized for every T, and therefore all it can do is accept a pointer, where that pointer is to the heap
Yes, in theory, we could just point to the stack, but there's no lifetime constraints on interfaces like that so it's not safe to do so. The interface could be saved to a field, for example, and then suddenly you have a field pointing at invalid memory
You'll likely need to use the simd instructions to enable them, because the compiler will have a difficult time seeing optimizable code through your abstractions otherwise
you know the exact type there, because of the way the constaint is set up
What?
IFoo<T>
will always have to be a T
IFoo<T> where T :struct, IFoo<T>
you can deduce at compile time that if you pass an IFoo<T>
, it will always have to be a T
because of the self reference, right?No
in theory
No
I mean, in practice, we'd tell you that you did a dumb by implementing
IFoo<SomeOtherIFoo>
On SomeFirstFoo
But there's nothing preventing you from doing thatyou can't due to the constraint though
Yes you can
how though
I can't think of an example
Again, if you were to do this in practice, you did a dumb
But you can do it
right
thanks for the example