4 ms·
ECS can also be implemented in functional or imperative languages, and it often is. The fact that ECS can be implemented in OOP languages doesn't make it an OO
by ratww 5y ago
ECS can also be implemented in functional or imperative languages, and it often is.
The fact that ECS can be implemented in OOP languages doesn't make it an OOP pattern, only that OOP languages have Turing-completeness. You could also write Pure-FP code or implement Prolog in an OOP language, or vice-versa.
> If you move the global functions to the entity objects themselves, you end up with OOP.
You're probably talking about moving the global functions (also called Systems) into the the Component objects. Entities in ECS are normally just integers to which components are attached to, the global functions you're talking to correspond to
This is possible for the simplest usages of ECS, however this is very limiting. One of the most important aspects of ECS, especially in modern frameworks, is the possibility of Systems (the "global functions") to operate in more than one kind of Component at a time.
For example: a collision detection System might want to operate on both "Position" and "Visibility" Components to avoid performing collision detection on invisible components.
This ability is crucial to ECS for two reasons: to have good separation of concerns, but also for performance.
With your suggestion in OOP, you would have to do that with multiple inheritance, or maybe by picking one Component to host the System and break encapsulation.
- jayd16 5y agoWhy do critics think looping over an array is somehow incomprehensible in OO and must be replaced with inheritance or something? Most ECS implementations are in OO languages. In Unity/C#, those systems are objects those arrays holding component information are even objects! Its really not a stretch for OOP. Its just a design pattern.
- ratww 5y agoECS is doing a bit more than looping over arrays, though. In modern production ECS systems there's often the case where a System acts over two or more Components is very common, and looping itself is not good enough for those cases (because you get O(n^2), O(n^3), O(n^4), etc, etc complexity), so it's nowhere near as simple as that. Like I said, it's possible to implement anything that is computable in any Turing-complete language. The fact that there are some ECS implementations in OOP languages speaks more to the popularity of those languages, rather than their capabilities or suitability to having ECS implemented in it. Of course ECS is going to need classes in languages that don't allow structs. Of course ECS is going to need classes in languages that don't allow freestanding functions. But that's doesn't mean that everything that is implemented in an OOP language can be considered just another OOP pattern. ECS is a more foundational way of organising code, in the same space as OOP itself. One of OOP features is encapsulation: data and methods living together. ECS enforces the complete opposite: complete separation. Another OOP feature is inheritance. ECS removes inheritance and replaces with composition. If one says that ECS a just another design pattern, then it's only fair to say that OOP is also just a design pattern in itself, since I could implement OOP itself in C (see Linux Kernel), Haskell or ECS if I wanted.
- kaba0 5y ago> If one says that ECS a just another design pattern, then it's only fair to say that OOP is also just a design pattern in itself, since I could implement OOP itself in C (see Linux Kernel), Haskell or ECS if I wanted. Well, it is? What do you mean by looping itself? How is having a struct dissimilar to having an object iterated, especially with C++ essentially having barely any difference between a struct and a class?
- ratww 5y ago> Well, it is? If you say so we can agree on that, yes. :) > What do you mean by looping itself? I mean that that ECS is not merely looping over an array like GP claimed. In production ECS, Systems normally act on more than one kind of Component, so "iterating over the array" of components is not feasible. Iterating over entities kinda kill the performance and data locality too, so you need something smart closer to "materialised SQL views" to get performance. > How is having a struct dissimilar to having an object iterated, especially with C++ essentially having barely any difference between a struct and a class? I never said it was. I just said that merely using a "class" doesn't make something an OOP pattern, especially if the implementor has no choice over which programming feature to use.
- kaba0 5y agoThanks for the details! Though wouldn’t using arrays of structs kill the performance the same way as array of objects do (stack-allocated ones)? So, one would essentially have to have a SOA, or — the OOP abstraction: a class of arrays that enclose this hot loop of code, making the implementation opaque to a calling code.
- ratww 5y ago> Though wouldn’t using arrays of structs kill the performance the same way as array of objects do (stack-allocated ones)? Not really. Components are long-lived so they're not allocated on the stack. And contiguous arrays of structs/objects is the best case for cache locality, that's the entire performance case of ECS.
- bccdee 5y agoBeing written in an object-oriented language doesn't make code object-oriented. I could write Java using classes as (namespaces for stateless functions) XOR (structs with no methods), and while it'd still technically all be objects and methods, in practice it wouldn't embody the spirit of OOP at all. It is in keeping with the spirit of OOP to wrap up different entities' data in separate objects and have them interact with each other through methods. Exposing all of every entity's data to the world and letting unaligned actors unilaterally mutate many entities' state with no middle man is very un-OO, even if you dress it up in classes and methods.
- samsquire 5y agoFunctions grouped with data is inherently OOP. Even if you don't interact with a graph of objects in a class, you're still using OOP if you define methods on your class and use those methods to interact with fields.
- bccdee 5y agoA method on a class is just syntactic sugar for a function with an argument. It takes more than just "the presence of methods" for something to be OOP.
- samsquire 5y agoIsn't the grouping of methods with data a core fundamental principle of OOP? Even if it is syntactic sugar, Variables, Types, Classes, functions, method calls, structs are just syntactic sugar too. It just so happens that the syntactic sugar of grouping functions with data is OOP.
- deleted 5y ago[deleted]
- jayd16 5y ago>Exposing all of every entity's data to the world and letting unaligned actors unilaterally mutate many entities' state But that is NOT the pattern. Entities are ids, they have component tags that opt entities into some functionality and the systems encapsulate and track the mutable state that system controls. If you want to start sharing ownership of mutable state, that basically comes down to an implementation detail. Unity's ECS system does NOT let "unaligned actors unilaterally mutate many entities' state with no middle man." One could perhaps implement it that way if they so choose. It's just a matter of taste because, again, the design pattern is not inherently OO or non-OO.