5 ms·
Making everything an object is a cute idea but the fact of the matter is, most of the time data is just data, there's no associated behavior. Lets say you have
by sirwhinesalot 3y ago
Making everything an object is a cute idea but the fact of the matter is, most of the time data is just data, there's no associated behavior.
Lets say you have a Player object who has an Inventory (can also be an object) and an inventory contains items like Swords and Bows etc. When a player wielding a sword takes a swing at an enemy, a particular animation has to play, and sword swing and sword hit sound effect has to play.
Which object contains the code that performs the rendering of the animation? Is there an "Animation" object that contains it? Does it call some setPosition/setRotation object in the sword and the player? Does the Animation object know how to call the appropriate Metal/Direct3D/Vulkan APIs or is that another object?
Or is the right solution to have an animation subsystem that doesn't care at all about "players" or "swords" and is only concerned with mesh data and how to transform it? Answer: the latter, which is what every game engine that wants to be even remotely efficient does.
That's not to say the Smalltalk idea of building larger systems out of smaller systems communicating via message passing is bad or anything, the problem is the OO idea of tying data to behavior. There isn't a single OO codebase out there without POD objects.
- trashburger 3y agoThere is in fact associated behavior; it is just moved off the object in an effort to avoid the after-effects of many languages which implement "OOP". Behavior doesn't have to be part of the object directly, in fact I support your idea that objects can be inert, but behavior inheritance is still an extremely useful concept even within the scenario you propose. As for your specific example, you don't have to add the behavior of actually playing the sound or animating to your `sword` or `player`; I never suggested that the objects themselves having to perform effects being an inherent part of object programming. Maybe you can send `player wieldedWeapon attackSprite` (or `attackMesh`, I'm fond of 2D platformers better :) and then the scene can ask the animation to render itself, same with `player target hurtSound` and `player wieldedWeapon attackSound` and then the sound object can be asked to play itself with a given `audioContext`. Here, we're being as declarative as can be and still giving the objects the freedom to behave however they want within the bounds of the contract they adhere to. So an object programming style does not, in fact, preclude you from making "POD objects"; it only says that the behavior of an object should be exposed through the object itself, rather than reflectively deciding on what the object should do from the outside.
- sirwhinesalot 3y agoNo, I disagree, because the right behavior is not determined by a single object but by a combination of factors. For example when the sword strikes an enemy all of the following need to happen: - The check that the "enemy" is even a valid target (who decides that? The player? What if certain enemies are immune to slashing attacks? The sword then? What about the enemy making the decision? What if it depends on the armor the enemy is wearing, does the armor decide?) - The calculation of the position of where the sword impacted the enemy (who calculates that? it depends on the animation calculation results, the size and shape of the sword and of the enemy, etc.) - The sound that plays depends on the type of equipment the enemy has (leather armor vs steel armor) and on the weapon of the player (a sword or a hammer would have different sounds). - The actual playback of the sound depends on all of the decisions above (the animation, the collision, the materials involved in the collision). At no point, in any of this, are there messages between these objects. The entities that have to make these calculations depend on multiple data sources, none of which belong to them, that is, the behavior is not associated with the data. An animation doesn't render itself (rendering requires a rendering context, mesh data, texture data, shaders, etc., who owns them?). A sound doesn't play itself. Collisions don't calculate themselves. Inert objects don't inherit behavior because they have no behavior, systems do. And systems are effectively "manager" objects (AnimationManager, AudioManager, CollisionManager, etc.), widely considered a bad practice in OO circles. Systems should indeed support behavior inheritance (I might want multiple different implementations of an AudioManager for different targets or with/without surround sound support, etc.) and since their internal data is hidden (i.e. operating system resources), they are very much objects and working with them is OO programming. But the rest of the system is not OO, it's very much plain old data being computed upon by plain old functions, and that has nothing to do with OO nor does it need any kind of inheritance. Even in Smalltalk you see this issue happening. Ints and Doubles respond to messages to implement arithmetic, but for example reading an integer from a stream is a method of the Number class that takes an integer radix and a Stream as input. Why is it not a method of the integer radix or of the stream? Why can't different streams decide how to parse themselves into integers? Because the whole concept of associating behavior here is silly. readFrom is a function.
- 3y ago
- munificent 3y ago> Making everything an object is a cute idea but the fact of the matter is, most of the time data is just data, there's no associated behavior. Data is just objects that don't happen to have any behavior. You can look at it as there being a continuum between data and behavior: * Purely just storing raw uninterpreted bits in memory and letting anything read and poke at them. * Storing raw data in memory but having an API that ensures that the data is in a valid state and maintains invariants. * Encapsulating data behind an API that gives you flexibility to change the representation without breaking users. * Attaching additional behavior that happens to use that data directly to the type that stores the data. Object-oriented languages support the full continuum, but the language itself certainly doesn't require you to go all the way for every type. Different kinds of data and different domains will naturally fit certain points on this continuum. When you say, "There isn't a single OO codebase out there without POD objects", I consider that a feature of object-oriented languages: They are flexible enough to model a range of state/behavior policies.
- dgb23 3y agoI really like this this perspective but I think it’s more multi dimensional. Often data only needs to be read so new data can be produced. There’s no need for encapsulation here. If you want to ensure that you’re dealing with data that has certain properties then you can do that with types, schemas or simply read it. Encapsulation at a lower level is needed when you mutate state or otherwise own resources and possibly multiple things need to be updated in tandem. In this case you want operational semantics and not look at the innards of the data. So the interface you want describes behavior. And then there is another level where you only care about coordination of messages. The interface is not the data/state behind whoever produces or reads them. You don’t even care about behavior anymore.
- sirwhinesalot 3y agoAn object without behavior is not an object, it's a self-contradictory statement. Objects are a pattern that appears in all languages (if you are implementing a plugin API of any sort you need to have hidden data and a shared interface). A language having OO features only makes this easier. Same with FP, you can do OO and FP in C, all FP means is that your functions don't have hidden side effects. If you make a Point class with getters and setters for its internal data, you've just emulated a record type in a really dumb and inefficient way. The whole "you could replace the internal representation with polar coordinates" example never ever happens.