Ed Marty
Ed Marty

Reputation: 39690

C#: Should I use out or ref to get this struct back?

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

Answers (5)

user541686
user541686

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

tvanfosson
tvanfosson

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

Hans Passant
Hans Passant

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

escargot agile
escargot agile

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

Andrew Hare
Andrew Hare

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

Related Questions