26
\$\begingroup\$

I get that sometimes you need properties, like:

public int[] Transitions { get; set; }

or:

[SerializeField] private int[] m_Transitions;
public int[] Transitions { get { return m_Transitions; } set { m_Transitions = value; } }

But my impression is that in game development, unless you have a reason to do otherwise, everything should be nearly as fast as possible. My impression from things I've read is that Unity 3D is not sure to inline access via properties, so using a property will result in an extra function call.

Am I right to constantly ignore Visual Studio's suggestions to not use public fields? (Note that we do use int Foo { get; private set; } where there is an advantage in showing the intended usage.)

I'm aware that premature optimization is bad, but as I said, in game development you don't make something slow when a similar effort could make it fast.

\$\endgroup\$
  • 34
    \$\begingroup\$ Always verify with a profiler before believing something is "slow". I was told something was "slow" and the profiler told me it had to execute 500,000,000 times to lose a half second. As it would never execute more than a few hundred times in a frame, I decided it was irrelevant. \$\endgroup\$ – Almo Aug 15 at 13:46
  • 5
    \$\begingroup\$ I've found that a little bit of abstraction here and there helps to apply low-level optimizations more widely. For instance, I've seen numerous plain C projects using various kinds of of linked-lists, which are dreadfully slow compared to contiguous arrays (e.g. the backing for ArrayList). This is because C has no generics, and these C programmers likely found it easier to repeatedly re-implement linked-lists than to do the same for ArrayLists's resizing algorithm. If you come up with a good low-level optimization, encapsulate it! \$\endgroup\$ – hegel5000 Aug 15 at 17:46
  • 3
    \$\begingroup\$ @Almo Do you apply that same logic to operations that occur in 10,000 different places? Because that is class member access. Logically you should be multiplying the performance cost by 10K before deciding that class of optimization doesn't matter. And 0.5 ms is a better rule of thumb for when the performance of your game will be ruined, not half a second. Your point still stands, though I don't think the right action is as clear as you make it out to be. \$\endgroup\$ – piojo Aug 16 at 3:08
  • 5
    \$\begingroup\$ You have 2 horses. Race them. \$\endgroup\$ – Mast Aug 16 at 11:48
  • \$\begingroup\$ @piojo I do not. Some thought must always go into these things. In my case, it was for loops in UI code. One UI instance, few loops, few iterations. For the record, I upvoted your comment. :) \$\endgroup\$ – Almo Aug 16 at 16:14
44
\$\begingroup\$

But my impression is that in game development, unless you have a reason to do otherwise, everything should be nearly as fast as possible.

Not necessarily. Just like in application software, there is code in a game which is performance-critical and code which is not.

If the code is executed several thousand times per frame, then such a low-level optimization might make sense. (Although you might first want to check first if it is actually necessary to call it that often. The fastest code is code you don't run)

If the code is executed once every couple seconds, then readability and maintainability is far more important than performance.

I've read is that Unity 3D is not sure to inline access via properties, so using a property will result in an extra function call.

With trivial properties in the style of int Foo { get; private set; } you can be pretty certain that the compiler will optimize the property wrapper away. But:

  • if you actually have an implementation, then you can not be that sure anymore. The more complex that implementation, the less likely that the compiler will be able to inline it.
  • Properties can hide complexity. This is a double-edged sword. On the one hand, it makes your code more readable and changeable. But on the other hand, another developer who accesses a property of your class might think they are just accessing a single variable and not realize how much code you've actually hidden behind that property. When a property starts to become computationally expensive, then I tend to refactor it into an explicit GetFoo() / SetFoo(value) method: To imply that there is a lot more happening behind the scenes. (or if I need to be even more sure that others get the hint: CalculateFoo() / SwitchFoo(value))
\$\endgroup\$
  • \$\begingroup\$ Accessing a field within a non-read-only public field of structure type is fast, even if that field is within a structure that is within a structure etc., provided that the top-level object is either a non-read-only class field or a non-read-only free-standing variable. Structures can be quite large without adversely affecting performance if these conditions apply. Breaking this pattern will cause slowdown proportional to structure size. \$\endgroup\$ – supercat Aug 15 at 20:06
  • 5
    \$\begingroup\$ "then I tend to refactor it into an explicit GetFoo() / SetFoo(value) method:" - Good point, I tend to move heavy operations out of properties into methods. \$\endgroup\$ – Mark Rogers Aug 15 at 20:53
  • \$\begingroup\$ Is there a way to confirm that the Unity 3D compiler makes the optimization you mention (in IL2CPP and Mono builds for Android)? \$\endgroup\$ – piojo Aug 16 at 5:02
  • 9
    \$\begingroup\$ @piojo As with most performance questions, the simplest answer is "just do it". You have the code ready - test the difference between having a field and having a property. The implementation details are only worth investigating when you can actually measure an important difference between the two approaches. In my experience, if you write everything to be as fast as possible, you limit the available high level optimizations, and just try to race the low level parts ("can't see forest for the trees"). E.g. finding ways to skip Update entirely will save you more time than making Update fast. \$\endgroup\$ – Luaan Aug 16 at 8:16
9
\$\begingroup\$

When in doubt, use best practices.

You are in doubt.


That was the easy answer. Reality is more complex, of course.

First, there's the myth that game programming is ultra super high performance programming and everything has to be as fast as possible. I classify game programming as performance aware programming. The developer must be aware of performance constraints and work within them.

Second, there's the myth that making every single thing as fast as possible is what makes a program run fast. In reality, identifying and optimizing bottlenecks is what makes a program fast, and that is much easier/cheaper/faster to do if the code easy to maintain and modify; extremely optimized code is hard to maintain and modify. It follows that in order to write extremely optimized programs, you have to use extreme code optimization as often as needed and as rarely as possible.

Third, the benefit of properties and accessors is that they are robust to change, and thus make code easier to maintain and modify - which is something you need to write fast programs. Want to throw an exception whenever someone wants to set your value to null? Use a setter. Want to send a notification whenever the value changes? Use a setter. Want to log the new value? Use a setter. Want to do lazy initialization? Use a getter.

And fourth, personally I don't follow Microsoft's best practice in this instance. If I need a property with trivial and public getters and setters, I just use a field, and simply change it to a property when I need to. However, I very rarely need such a trivial property - it's far more common that I want to check for boundary conditions, or want to make the setter private.

\$\endgroup\$
2
\$\begingroup\$

It is very easy for the .net runtime to inline simple properties, and often it does. But, this inlining is normally disabled by profilers, hence it is easy to be misled and think that changing a public property to a public field will speed up software.

In code that is called by other code that will not be recompiled when your code is recompiled there is a good case for using properties, as changing from a field to a property is a breaking change. But for most code, other than being able to set a breakpoint on the get/set, I have never seen benefits in using a simple property compared to a public field.

The primary reason I used properties in my 10 years as a professional C# programmer was to stop other programmers telling me I was not keeping to the coding standard. This was a good tradeoff, as hardly ever was there a good reason not to use a property.

\$\endgroup\$
2
\$\begingroup\$

Structs and naked fields will ease interoperability with some not managed APIs. Often you will find that the low level API wants to access the values by reference, which is good for performance (as we avoid an unnecessary copy). Using properties is an obstacle to that, and often times the wrapper libraries will do copies for ease of use, and sometimes for security.

Because of that, you will often get better performance having vector and matrix types that do not have properties but naked fields.


Best practices are not creating in vaccum. Despite some cargo cult, in general best practices are there for a good reason.

In this case, we have a couple:

  • A property allows you to change the implementation without changing the client code (on a binary level, it is possible to change a field to a property without changing the client code on a source level, however it will compile to something different after the change). That means, that by using a property from the start, the code that references yours will not have to be recompiled just to change what the property does internally.

  • If not all the possible values of the fields of your type are valid states, then you do not want to expose them to client code that code modify it. Thus, if some combinations of values are invalid, you want to keep the fields private (or internal).

I have been saying client code. That means code that calls into yours. If you are not making a library (or even making library but using internal instead of public), you can usually get away with it and some good discipline. In that situation the best practice of using properties is there to prevent you from shooting yourself in the foot. Furthermore, it is much easier to reason about code if you can see all the places where a field can change in a single file, instead of having to worry on whatever or not it is being modified somewhere else. In fact, properties are also good to put breakpoints when you are figuring out what went wrong.


Yes, there is value is seeing what is being done int industry. However, do you have a motivation to go against the best practices? or are you just going against the best practices – making the code harder to reason about – just because somebody else did it? Ah, by the way, "others do it" is how you start a cargo cult.


So... Is your game running slow? You are better of devoting time to figure out the bottleneck and fixing that, instead of speculating what could it be. You can rest assured that the compiler will do plenty of optimizations, because of that, chances are you are looking at the wrong problem.

On the flip side, if you are deciding what to do to begin with, you should worry about what algorithms and data structures first, instead of worrying about smaller details such as fields vs properties.


Finally, do you earn something by going against best practices?

For the particulars of you case (Unity and Mono for Android), does Unity takes values by reference? If it doesn't, it will copy the values anyway, no performance gain there.

If it does, if you are passing this data to an API that takes ref. Does it make sense to make the field public, or you could make the type able to call the API directly?

Yes, of course, there could be optimizations that you could do by using structs with naked fields. For example, you access them with pointers Span<T>, or similar. They are also compact on memory, making them easy to serialize to send over the network or put in permanent storage (and yes those are copies).

Now, have you picked the right algorithms and structures, if they turn out to be a bottleneck, then you decide what is the best way to fix it... that could be structs with naked fields or not. You will be able to worry about that if and when it happens. Meanwhile you can worry about more important matters such as making a good or fun game worth playing.

\$\endgroup\$
1
\$\begingroup\$

...my impression is that in game development, unless you have a reason to do otherwise, everything should be nearly as fast as possible.

:

I'm aware that premature optimization is bad, but as I said, in game development you don't make something slow when a similar effort could make it fast.

You are right to be aware that premature optimisation is bad but that is only half the story (see the full quote below). Even in game development, not everything needs to be as fast as possible.

First make it work. Only then, optimise the bits that need it. That's not to say that the first draft can be messy or needlessly inefficient but that optimisation is not a priority at this stage.

"The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming." Donald Knuth, 1974.

\$\endgroup\$
1
\$\begingroup\$

For basic stuff like that, the C# optimizer's going to get it right anyway. If you worry about it (and if you worry about it for more than 1% of your code, you're doing it wrong) an attribute was created for you. The attribute [MethodImpl(MethodImplOptions.AggressiveInlining)] greatly increases the chance a method will be inlined (property getters and setters are methods).

\$\endgroup\$
0
\$\begingroup\$

Exposing structure-type members as properties rather than fields will often yield poor performance and semantics, especially in cases where structures are actually treated as structures, rather than as "quirky objects".

A structure in .NET is a collection of fields duct-taped together, and which can for some purposes be treated as a unit. The .NET Framework is designed to allow structures to be used in much the same way as class objects, and there are times this can be convenient.

Much of the advice surrounding structures is predicated on the notion that programmers will be wanting to use structures as objects, rather than as taped-together collections of fields. On the other hand, there are many cases where it can be useful to have something that behaves as a taped-together bunch of fields. If that's what one needs, the .NET advice will add needless work for programmers and compilers alike, yielding worse performance and semantics than simply using structures directly.

The biggest principles to bear in mind when using structures are:

  1. Don't pass or return structures by value or otherwise cause them to be copied unnecessarily.

  2. If principle #1 is adhered to, large structures will perform just as well as small ones.

If Alphablob is a structure containing 26 public int fields named a-z, and a property getter ab which returns the sum of its a and b fields, then given Alphablob[] arr; List<Alphablob> list;, the code int foo = arr[0].ab + list[0].ab; will need to read fields a and b of arr[0], but will need to read all 26 fields of list[0] even though it will ignore all but two of them. If one wanted to have a generic list-like collection that could work efficiently with a structure like alphaBlob, one should replace the indexed getter with a method:

delegate ActByRef<T1,T2>(ref T1 p1, ref T2 p2);
actOnItem<TParam>(int index, ActByRef<T, TParam> proc, ref TParam param);

which would then invoke proc(ref backingArray[index], ref param);. Given such a collection, if one replaces sum = myCollection[0].ab; with

int result;
myCollection.actOnItem<int>(0, 
  ref (ref alphaBlob item, ref int dest)=>dest = item,
  ref result);

that would avoid the need to copy portions of the alphaBlob that aren't going to be used in the property getter. Since the passed delegate doesn't access anything other than its ref parameters, the compiler can pass a static delegate.

Unfortunately, the .NET Framework doesn't define any of the kinds of delegates needed to make this thing work nicely, and the syntax ends up being kind of a mess. On the other hand, this approach makes it possible to avoid copying structures needlessly, which will in turn make it practical to perform in-place actions on large structures stored within arrays, which is the most efficient way of accessing storage.

\$\endgroup\$
  • \$\begingroup\$ Hi, did you post your answer to the wrong page? \$\endgroup\$ – piojo Aug 16 at 16:56
  • \$\begingroup\$ @pojo: Perhaps I should have made clearer that the purpose of the answer is to identify a situation where using properties rather than fields is bad, and identify how one can achieve the performance and semantic advantages of fields, while still encapsulating access. \$\endgroup\$ – supercat Aug 16 at 17:42
  • \$\begingroup\$ @piojo: Does my edit make things clearer? \$\endgroup\$ – supercat Aug 16 at 17:55
  • \$\begingroup\$ "will need to read all 26 fields of list[0] even though it will ignore all but two of them." what? Are you sure? Have you checked the MSIL? C# nearly always passes class types by reference. \$\endgroup\$ – pjc50 Aug 16 at 20:23
  • \$\begingroup\$ @pjc50: Reading a property yields a result by value. If both the indexed getter for list and the property getter for ab are both in-lined, it might be possible for a JITter to recognize that only members a and b are needed, but I'm unaware of any JITter version actually doing such things. \$\endgroup\$ – supercat Aug 16 at 21:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.