Design patterns for hacking together prototypes: object dictionaries
web.eecs.utk.edu
web.eecs.utk.edu
The first time I read about ECS I thought it was a completely crazy idea, but after trying it I realized that I was able to have extreme low-coupling and complete separation of concerns. It was great for hacking things, but in the long term it was also great for maintenance and code reuse! I never felt this way about OOP, ever.
In this case however it seems that the "Entity Management" part is ad-hoc, with Editors themselves putting things on the dictionaries. Ooops :)
EDIT: I think one can get a lot of mileage out of something like this if the dictionary management code is properly encapsulated in an isolated module/class. Just an idea.
An ECS is fundamentally a column store for one really wide table. It’s optimized for performing batch operations on sparsely-populated columns in that table.
This is more like defining a database index: these dictionaries are using some kind of computed result as the key, allowing you to lookup objects by this result without a linear scan through all relevant objects.
What's in the article is really closer to "relational data model" than all of these above. All these dictionaries are essentially implementing SQL selects. The "relational data model" lens to viewing ECS is that it's essentially giving each component its own table, and doing plenty of joins.
I find this really interesting, and my current side project is a roguelike game that focuses only on that part - relegating all game ECS into an in-memory SQLite database. I decided to go that way after trying to improve my last attempt at an ECS framework, only to realize I'm essentially hand-coding SQL indexes, and that's not something I want to do when I'm prototyping a game.
I work primarily in Python, and one thing I see all the time is using dictionaries instead of method arguments. The thought is that when the method evolves over time, you can just add a field to the dictionary. What ends up happening is this dictionary argument is passed up and down the call stack for every nested method call, and sometimes elements are added, edited, or deleted on the way.
Whenever I have to do a refactor of methods like this, it is awful trying to figure out the state of the dictionary, what was originally supposed to be in it, and if it's returned, which parts are actually relevant.
(defn foo [{:keys [bar baz]}]
;; do something...
)
(foo {:bar 1 :baz 2})
This isn't as good as a type signature, but makes it easy to know what the dependencies to a function are.Those who don't understand Unix are condemned to reinvent it, poorly. - Henry Spencer
[0]
This can be useful when you want to keep an association to an object but you want to ownership of that list of associations in a different object but I certainly would not make these global.
What's next? Forget numbers, just String everything because you'll save time serializing?
It's the same in every discipline, at some point you need to transcend the rules to go anywhere.