I've read quite a few articles about DOD. I get how DOD is great but there are reasons OOP is still around (surely?) I suppose I'm still hung up on, what are the benefits of OOP that I'm missing? It seems like there are reasons OOP is so ingrained. I can see a couple of reasons that are environmental. For instance, OOP is taught in schools because students are often taught to program before they're taught about compu…
A lot of languages have OOP built into them. If want to use patterns like polymorphism it’s the tool on hand. Associating data with functions is helpful for organization as well.
An Introduction to Data Oriented Design with Rust
41–50 of 161 posts
Re: An Introduction to Data Oriented Design with Rust
#42How much of it you'd recommend to think of in advance when working on something vs the opposite guideline of avoiding premature optimization?
It's not premature optimization since this is not something you can bolt on later.
Question is, how deep to go first.
Re: An Introduction to Data Oriented Design with Rust
#43The cost to legibility for the vectorization seems high. I wish there were a way to get the best of both worlds, i.e. specify the type you want and have it striped so that the struct is then vectorified.
Isn’t that a feature in Jai?
Re: An Introduction to Data Oriented Design with Rust
#44Earlier quoted context omitted.
The interesting thing to me from these patterns is the possibility of using proc_macros to write code in the "array of structs" style while the code gets desugared to "struct of arrays". I don't know how beneficial that would be, but having it as an option would make this pattern more approachable to people that would otherwise not use it, due to verbosity, mental model mismatch or any other reason people might have…
> The interesting thing to me from these patterns is the possibility of using proc_macros to write code in the "array of structs" style while the code gets desugared to "struct of arrays". This is not possible in the general case, because you can have a general pointer/reference to a single struct in an "array of structs" but a "struct of arrays" can only be accessed by indexing each array separately. So only very si…
A general pointer/reference type that might point to a single struct in "array of structs" can be transformed to a "wide pointer" representation as pointer/reference to the array and index into the array.
If analysis can't prove the pointer is constant, then the representation will be an opaque wide token outside the transformed code, which is fine. If it can prove the pointer is constant, the run time representation does not need to be wide, as it's just the index, also opaque outside the transformed code.
There's no need to have a representation as a regular pointer, because there's no way the struct pointer/reference type can be dereferenced outside of transformed code anyway, only passed around.
Re: An Introduction to Data Oriented Design with Rust
#45Earlier quoted context omitted.
As always, it depends on the problem you're solving. A 2x speedup in the inner loops of a game can be a very big deal. And for business workloads, I occasionally spend time babysitting clusters running batch jobs. A 2x performance increase in the right inner loop might save a couple hundred dollars per run. So certainly, profile before you optimize, as the article demonstrates. But 2x speedups can be worth applying a…
The interesting thing to me from these patterns is the possibility of using proc_macros to write code in the "array of structs" style while the code gets desugared to "struct of arrays". I don't know how beneficial that would be, but having it as an option would make this pattern more approachable to people that would otherwise not use it, due to verbosity, mental model mismatch or any other reason people might have…
In archetype-based ECS libraries (which the ecosystem seems to be converging on or near) you write a query asking for a particular subset of "component" types, where each type is stored in its own array(s), and then for each iteration of the query you get back one reference to each component type.
As a result, all the extra zipping (which I'm assuming is what people find less readable about the article's example) is handled in the query implementation, and you get this sort of hybrid between the two, syntactically speaking:
for (location, velocity, acceleration) in players.query::() {
*location = (
location.0 + velocity.0,
location.1 + velocity.1,
);
*velocity = (
velocity.0 + acceleration.0,
velocity.1 + acceleration.1,
);
}
Some libraries even let you write a query as a struct with a #[derive] on it, rather than a tuple, so you can use essentially the same syntax as the "OOP" example from the article, rather than destructing the "fields" up front.Re: An Introduction to Data Oriented Design with Rust
#46Earlier quoted context omitted.
It's not premature optimization since this is not something you can bolt on later.
A lot of optimizations can't be easily added later without redesign. But it doesn't mean they are always necessary. Question is, how deep to go first.
Re: An Introduction to Data Oriented Design with Rust
#47Earlier quoted context omitted.
DOD generally implies a high level of coupling on the system. That's it's biggest weakness. It also pushes even more data management problems onto programmers which makes it easy to get things wrong. You take those downsides and you trade them for higher performance. Now, that doesn't mean that you can't have hybrid systems and get most of the benefits of both worlds. It does, however, mean that you will end up with…
> DOD generally implies a high level of coupling on the system. That's it's biggest weakness. I'm not sure I understand what you mean by DOD generally implies a high level of coupling? Could you perhaps elaborate a bit?
Suddenly, you want "struct Point3D {int x; int y; int z;}". How would you change the code?
In OOP, maybe you'd compose a Point3D as such: struct Point3D { Point xy; int z; }; You can now "capture" all of the Point xy; functionality, and extended it to a 3rd "z" coordinate just fine. All old Point code still works, and you have a few functions that work with Point3D now (maybe with a bit of redundant wrapper functions, but such code is straight forward)
The equivalent in DOD seems less obvious. You'd have to make a new "z" array. But the arrays of Point and Point3d wouldn't line up anymore. (If you had 300 Points, and 20 Point3Ds, is Point#315 a Point3D, or is it a Point? Do you "pad" the "z" arrays to ensure that the struct-of-arrays line up?)
There's no obvious way to benefit from a "z-vector", extending the functionality off of your Point to Point3D. I think the DOD design would create a 3rd "z-vector", and shove a "dummy value" into z for all of the points, to make sure all the vectors would have an ideal set of indexes.
Which demonstrates the coupling factor: its not really easy to compose objects in DOD. While in OOP, composing and inheriting classes and objects is the very point.
Re: An Introduction to Data Oriented Design with Rust
#48The cost to legibility for the vectorization seems high. I wish there were a way to get the best of both worlds, i.e. specify the type you want and have it striped so that the struct is then vectorified.
Re: An Introduction to Data Oriented Design with Rust
#49https://www.youtube.com/watch?v=rX0ItVEVjHc
Very enlightening and entertaining!
Re: An Introduction to Data Oriented Design with Rust
#50A lot more in-depth about caching, avoiding branching etc. can be found in this classic talk by Mike Acton who is Engine Director at Insomniac Games https://www.youtube.com/watch?v=rX0ItVEVjHc Very enlightening and entertaining!