Reputation: 39690
I'm not sure of the best way to ask this question, so I'll start with an example:
public static void ConvertPoint(ref Point point, View fromView, View toView) {
//Convert Point
}
This call is recursive. You pass in a point, it converts it relative to fromView
to be relative to toView
(as long as one is an ancestor of the other).
The call is recursive, converting the point one level at a time. I know, mutable structs are bad, but the reason I'm using a mutable point is so that I only need to create a single point and pass it along the recursive call, which is why I'm using ref. Is this the right way to go, or would it be better to use an out parameter, or simply declare the method to return a point instead?
I'm not very familiar with how structs are handled as opposed to classes in these circumstances. This is code being ported from Java, where point obviously had to be a class, so it made sense to use the same temporary point over and over rather than create a new point which had to be garbage collected at every call.
This may be a confusing question, and to heap on some more confusion, while I'm at it, should I keep a temporary static Point
instance around for quick conversions or would it be just as simple to create a new point whenever this method is called (it's called a lot)?
Upvotes: 4
Views: 2191
Reputation: 210445
Depends on what you're doing, and why you're doing it.
Structs in C# are not like classes in Java at all. They're just like primitive types in terms of speed and semantics. (In fact, the primitive types are structs in a sense.) There's really no cost to passing them around, so if this is optimizing for something that's not a problem yet, I suggest you just make the method return a Point
.
However, it's possible that passing around a copy of the struct will be slower in some cases, if the struct
is large or if this method is the bottleneck, possibly because you're calling it many times per second (which I doubt is the case here); in those cases, it makes sense to pass them by reference, but first you'd need to figure out if it's actually the bottleneck in the first place.
Notice, for example, that in Microsoft's XNA library, the Matrix
struct has two versions of the same method:
static void CreateLookAt(
ref Vector3 cameraPosition, ref Vector3 cameraTarget, ref Vector3 cameraUpVector,
out Matrix result)
static Matrix CreateLookAt(
Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector)
This is purely for a performance reason, but only because this method is being called many times per second, and Vector3
is a bit larger than a normal struct
.
So why exactly were you doing this? The answer depends on the reason why you wrote it like this in the first place, but for typical code, it shouldn't matter.
Upvotes: 1
Reputation: 532455
Structs should be immutable, so I would vote for returning a different Point from the method. If you need mutability, then you should make it a class and create a method on the class to convert it. A by-product of the latter could be changing the recursive descent into an iterative application of the transformations.
Upvotes: 1
Reputation: 941465
Fretting over the garbage collector is never not a mistake when dealing with short-lived objects such as the Point, assuming it is actually a class. Given that this is C#, it is likely to be a struct, not bigger than 16 bytes. In which case you should always write the method to return a Point. This gets optimized at runtime, the struct fits in cpu registers.
Only ever consider passing structs by ref when they are large.
Upvotes: 9
Reputation: 22379
As the point is a struct, I see no advantage in using ref
here. It will be copied multiple times on the stack anyway, so why not just return it? I think it will make the code more readable if you declare this method with Point
as the return type.
Upvotes: 0
Reputation: 351516
I tend to make everything a class to simplify things. If you find that this creates unwanted memory pressure in your application only then should you investigate a solution that involves a mutable struct.
The reason I say this is that the GC tends to be very good at optimizing collections around the needs of your app and mutable structs are a notorious headache. Don't introduce that headache if the GC can handle the memory pressure of multiple objects.
Upvotes: 1