views:

87

answers:

2

Basically I have checked out xna and some of slimdx (Promit :)), which has lots of structs. Pretty much all methods that looked like this:

public static Vector3 operator + ( Vector3 a, Vector3 b )

where doing stuff like:

Vector3 c = new Vector3 ( ... )

I am wondering if it makes sense to just do:

a.X += b.X
...

return a

Obviously #1 looks more sensible/reasonable, but #2 doesn't create a new Vector3 which is faster.

I think it's fast and as clear, if not more clear as #1.

Which one is better? Is there any problems with #2?

A: 

I really doubt that you're going to have to worry so much about performance that you need to do this. Do the #1.

"Premature optimization is the root of all evil." - Donald Knuth

McWafflestix
If he's working on games and graphics apps, performance matters much more than in typical business apps.
Reed Copsey
@Reed - but you should still profile and find your actual bottlenecks. If it's somewhere else, optimizing this bit isn't going to help.
Mark Brackett
Knuth didn't say "Premature optimization of business apps is the root of all evil."; you'll note that there's no qualification there. Once you profile, you'll find where your slowdowns are; prior to that, you're just guessing, and almost certainly reducing your code quality dramatically.
McWafflestix
@Mark - Yes, but we shouldn't use Knuth's quote to pretend perf issues do not exist. For games with XNA on the 360, garbage collection is usually a big deal, and programming idioms that avoid it are preferred.
Michael
Yes I am working on real time games and 3d apps, and really every second counts as far as I am concerned. But I know the line where a specific optimization is incredibly unrealistic for the gain it brings. But for this case, it was significant and personally I don't think #2 is more work or complex than #1.
Joan Venge
+1  A: 

The only problem with 2 is that, since Vector3 is a value type (for good reason, see Rico Mariani's blog for details), you can't edit in place when they're part of collections or being used as a property member.

For example, it's very common to have a List<Vector3> member, but if you do:

myList[150].X += ...;

It fails, since the indexer returns a NEW struct (value type semantics). It's usually safer with value types to treat them as immutable, which requires your first syntax.

Reed Copsey
Thanks Reed. I worded the question title wrong I guess. I meant changing the value that is passed, i.e not the original but the passed by ref copy.
Joan Venge
Joan: Normally, it's a good idea to treat value types as if they're immutable (.net design guidelines even suggests making things classes for that reason). Vector3's aren't, typically, in games - but that's for convience. The second syntax only works if the type is mutable, I try to avoid it just because it "looks like" a reference type. Perf. wise, they're typically identical after the JIT gets to them, though (although a specific situation may be different).
Reed Copsey
Can you elaborate how you'd use this fully in a method? Then I could give you tips from my experience (I'm a full-time 3D dev using C# - so this is right up my alley ;) )
Reed Copsey
Hey Reed, thanks for the help. I know mutable structs aren't favored but I had that idea when I first saw it done on xna and slimdx, etc. I will probably make them immutable so it might be invalid. But mutable structs, basically these operators are overloaded and then called for a+b, c+d, etc. It's just that #1 is gonna create a new extra value to return. But that value is gonna be passed by ref, so copied again, right?
Joan Venge
Joan: Since these are all value types, the new object is being created on the stack, and copied by value at the return. If you treat "a" as mutable, it needs to be copied at the method return, as well. Since your working with value types, the difference is very minor. With reference types, this would be different, but then doing #2 would change "a" on the caller side, which would have side effects - so you'd avoid it there, too. In theory, you can save one stack allocation by returning "a" directly, but there is a side effect here.
Reed Copsey
If you're using .NET 3.5sp1, modifying "a" inside of your method will prevent the JIT from inlining this routine. This will actually cause #1 to run more slowly. #2 is more likely to become a candidate for inlining. (pre 3.5sp1, methods which took structs as args never got inlined, so it doesn't matter there)
Reed Copsey
Thanks Reed. Can you please tell me more about your last comment? You mean #2 would be faster? But it modifies "a" directly.
Joan Venge
Sorry - I wrote that backwards - #1 is more likely to be inlined, hence faster, with a value type. If it doesn't get inlined, #2 will be faster.
Reed Copsey
Thanks Reed. ...
Joan Venge