3 ms·
I think you missed the real question: should the verb be `attack` or `defend` (i.e. "defend from", or "attacked by")? In class- or prototype-based OOP, we have
by chriswarbo 8y ago
I think you missed the real question: should the verb be `attack` or `defend` (i.e. "defend from", or "attacked by")?
In class- or prototype-based OOP, we have to choose between `knight.attack(mage)`, with the functionality living inside `knight`; or `mage.defend(knight)` with the functionality living inside `mage`.
> The action (verb), attack, is a function which makes decisions and has portability.
OOP discourages standalone functions, so this function would either have to be in the knight, in the mage or (I would argue even worse) some sort of `GameState` object.
- austincheney 8y agoI guess it would depend upon the rules at play and various other unspoken variables, but generically speaking I don't see the difference between attack and defend in this limited scenario. One agent is interacting with another. The same instruction set would apply if it were knight attacking mage or mage attacking knight. > OOP discourages standalone functions Oh how I detest OOP. Portability of atomic components is amazing. So is scope nesting. Its like driving to work whenever you want in any of your cars (or your neighbors) instead of checking out a car from a car model inherited by a sedan class inherited from Toyota car class when such a thing becomes available.
- chriswarbo 8y agoI agree that nether way around seems inherently better than the other, so it would depend on the specifics of that project. > The same instruction set would apply if it were knight attacking mage or mage attacking knight. Not necessarily! For example, a mage might cast long-range magic, whilst a knight would only have melee attacks. Where we make this distinction can affect our understanding, maintaining and extending of the code. Standard OOP practice would use an inheritance hierarchy to handle this difference, e.g. a `Character` class could have `RangedCharacter` and `MeleeCharacter` subclasses whose `attack` method handles the details of those sorts of attack; then `Knight` and `Mage` subclasses those, to specialise the parameters. The major problem with this is that we can't model multiple distinctions in this way; for example knights and mages might both be "noble", whilst trolls and imps are "evil". If we want `Knight` to inherit from both `MeleeCharacter` and `NobleCharacter` we'd need multiple inheritance, which is where things get tricky. More recent trends favour composition rather than inheritance, e.g. passing in an `Attack` argument during construction, with `RangedAttack` and `MeleeAttack` subclasses. Separate objects can be passed in for the `Noble`/`Evil` distinction. Of course, these are just standalone functions with more boilerplate ;) Mixins are somewhere inbetween, where we avoid some of the boilerplate chaperones ( https://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html https://steve-yegge.blogspot.com/2006/03/execution-in-kingdo... ) The CLOS approach, mentioned by others in these comments, lets us define verbs like `attack` outside of any particular class or mixin. We can then define it case-wise based on its arguments, like `attack(RangedCharacter, Character)` and `attack(MeleeCharacter, Character)`.
- austincheney 8y ago> Not necessarily! For example, a mage might cast long-range magic For me that is just a difference in data properties. The event is the actual attack. A ranged attack would be the distance between the two parties. A melee attack would have a distance of 1. A self-inflicted attack would have a distance of 0. If you attempt a melee attack from a different room the attack action still happens, but the other party receives no damage and probably no awareness of the attack. The handling of the action and consideration of the data is still the same regardless of who commits the action and who is the attacked party.