[swift-users] Comparing POP to OOP
Dave Abrahams
dabrahams at apple.com
Thu Feb 25 20:00:14 CST 2016
on Tue Feb 16 2016, Daniel Tartaglia <swift-users-AT-swift.org> wrote:
> Jon,
>
> Here’s the thing… Swift protocols are exactly equivalent to OO
> interfaces.
That's true of Objective-C protocols, but not of Swift protocols. The
only way it can be said of Swift protocols is if you never use them with
value types and you restrict yourself to the dynamically-dispatched
subset of what they provide (i.e. no self requirements or associated
types).
> Swift protocol extensions are exactly equivalent to global functions
> that take an object of the protocol type as a parameter.
>
> The only difference is in some syntactic sugar.
Also untrue. A constrained protocol extension can conditionally fulfill
a protocol requirement for a whole category of conforming types. You
can't do that with global functions (except operators, and it's a
horrible hack that we'll remove one day).
>
>> On Feb 15, 2016, at 8:13 PM, Jon Hoffman <hoffman.jon at gmail.com> wrote:
>>
>> Please excuse my ignorance on ECS. I did read though the link that
>> you sent and also a few other sites on ECS namely
>> https://en.wikipedia.org/wiki/Entity_component_system
>> <https://en.wikipedia.org/wiki/Entity_component_system> and
>> http://www.gamedev.net/page/resources/_/technical/game-programming/understanding-component-entity-systems-r3013
>> <http://www.gamedev.net/page/resources/_/technical/game-programming/understanding-component-entity-systems-r3013>.
>> It does appear that ECS design is a lot closer to POP then OOP based
>> on what I read however I may not fully understand ECS.
>>
>> Lets take a couple of land animals as examples. If we had a Lion,
>> it would attack either using it’s claws or it’s teeth. An Alligator
>> would use it’s teeth on land. A snake or spider would inject venom
>> into it’s victim while some snakes may also squeeze the victim to
>> death. With ECS, I believe we would have components for each type
>> of attack. Is that correct? Then we would add the component that
>> we need to our entity (animal).
>>
>> If my description is correct, then I believe this is very similar to
>> a POP design where we would use protocols to define the component
>> and protocol extensions to add the functionality. This would mean
>> we would have the BiteAttack, ClawAttack, VenomAttack and
>> SqeezeAttack protocols with protocol extensions to add the
>> functionality. Do I understand ECS correctly? This type of design
>> is very good where we break all of the components down into
>> individual types.
>>
>> One advantage to using POP to implement ECS is we would define the
>> requirements when we define the animal type. What I mean by that is
>> we would specify what protocols the type conforms to when we define
>> the type. This prevents developers from adding the wrong components
>> within the code. The draw back with using POP would be the type
>> definition could get pretty long because we would need to list all
>> of the protocols that a type needs to conform to.
>>
>> One point you made, if I understood you correctly, is that with POP
>> we would have larger types as compared to ECS however if we use
>> protocol extensions to add the functionality to our component types,
>> I do not believe our individual animals types would be much bigger
>> than the ECS ones.
>>
>> Do I understand the ECS design correctly?
>>
>> Jon
>>
>>> On Feb 15, 2016, at 5:51 PM, Adam Eberbach <aeberbach at me.com <mailto:aeberbach at me.com>> wrote:
>>>
>>> For a third approach take a look at
>>> http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/
>>> <http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/>
>>> and the following posts (5).
>>> Entity Component Systems avoid the problem of everything migrating
>>> up into the base class and the propagation of classes by separating
>>> aspects (attributes, things the entity has) of the entity into
>>> components. The entity itself is little more than a UUID handle to
>>> the components owned by that entity. In this example an alligator
>>> has a LandComponent and a SeaComponent. A System contains the code
>>> that acts on the data contained in those components and there is a
>>> system for each kind of component, for example a LandSystem that
>>> has code to make an entity move on land. Each update the System
>>> acts on every entity that has a component matching it.
>>>
>>> The description above is the more modern AAA-game ideal of ECS but
>>> there is disagreement about the fine points (of course!). Apple’s
>>> GameplayKit implements an older form of ECS like that developed by
>>> Scott Bilas for Dungeon Siege
>>> (http://scottbilas.com/games/dungeon-siege/
>>> <http://scottbilas.com/games/dungeon-siege/>) in 2003, where
>>> components have code and data.
>>>
>>> I think this is very like the POP idea… but perhaps cleaner since
>>> the System processes, subject to the usual sync issues, can be
>>> separate threads. Adding a behaviour or a new entity is as simple
>>> as choosing the right components, aggregating them into an entity
>>> and then adding that entity to the update loop. And it doesn’t
>>> matter how many aspects you add to a class - all the code is
>>> encapsulated in the System, all the data in the Component. The POP
>>> approach is pretty good but you still wind up with a very beefy
>>> class.
>>>
>>>> On 16 Feb 2016, at 6:21 AM, Jon Hoffman via swift-users <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
>>>>
>>>> Sorry for the misunderstanding, I see what you are doing now, you are using the command pattern, however I so see quite a bit of difference between your design and my POP design. The biggest is the number of types needed between the designs. For example, how the Lion attacks and moves on land is different than how the Alligator attacks and moves on land therefore you will need separate attack and movement types for each type of animal. This means that you will need a Alligator type and to go with that Alligator type you would need AlligatorLandAttack, AlligatorSeaAttack, AlligatorLandMove and AlligatorSeaMove types. You would also need the Lion type with a LionLandAttack and LionLandMove type. You would need these separate types for each animal you create. With my POP all of this logic would be encapsulated in a single types.
>>>>
>>>>
>>>> By encapsulating all of the logic into a single type your code will be easier to manage and also less error prone. For example, in your code there is nothing preventing a developer to accidentally adding the LionLandAttack type to the Alligator type and since that error could occur anyplace where an instance of the Alligator is created it could also be hard to track down.
>>>>
>>>>
>>>> One of the principles of Protocol-Oriented programming is making our code safer and easier to manage. Your code would work but I would still say that the POP code would be much easier to manage long term and would also be less error prone. That is my opinion and everyone will have their own.
>>>>
>>>>
>>>> On Mon, Feb 15, 2016 at 1:52 PM, Daniel Tartaglia <danielt1263 at gmail.com <mailto:danielt1263 at gmail.com>> wrote:
>>>> That’s easy to do by allowing an Animal to hold multiple modes. Yes, the code below uses a Protocol, but only as an OO interface.
>>>>
>>>> let alligator = Animal()
>>>> alligator.mode.append(Land())
>>>> alligator.mode.append(Sea())
>>>>
>>>> protocol Mode {
>>>> func attack() -> Bool
>>>> func move() -> Bool
>>>> }
>>>>
>>>> class Animal {
>>>> var modes: [Mode]
>>>> func attack() -> Bool {
>>>> for mode in modes {
>>>> if mode.attack() {
>>>> break
>>>> }
>>>> }
>>>> }
>>>> }
>>>>
>>>>
>>>>
>>>>> On Feb 15, 2016, at 1:43 PM, Jon Hoffman <hoffman.jon at gmail.com <mailto:hoffman.jon at gmail.com>> wrote:
>>>>>
>>>>> Thank you for the feedback however you cannot design the code as you describe, if I understand your explanation correctly, because one of the requirements is the animals may be apart of multiple categories. As the example in the post shows the alligator belongs to both the Land and the Sea categories. In you description that would mean that the Alligator type would need to be a subclass of both the Land and Sea superclasses which is not permitted. Remember that one of the drawbacks with OOP is a subclass can only inherit from one superclass.
>>>>>
>>>>> Jon
>>>>>
>>>>> On Mon, Feb 15, 2016 at 1:17 PM, Daniel Tartaglia <danielt1263 at gmail.com <mailto:danielt1263 at gmail.com>> wrote:
>>>>> (Reposting because I forgot to change the subject line. Hope that this is the correct thing to do.)
>>>>>
>>>>> I have to say John that I am not a fan of your OOP code. I would have written the OOP code very much like you wrote the POP version using the Strategy pattern.
>>>>>
>>>>> [Animal]<*>--->[Mode]
>>>>> ^
>>>>> |
>>>>> +------+------+
>>>>> | | |
>>>>> [Land] [Sea] [Air]
>>>>>
>>>>>
>>>>> (View the above with a mono-spaced font.)
>>>>>
>>>>> In essence, I see no difference. There may be a difference, but I don’t think your example presents one.
>>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-users mailing list
>>>> swift-users at swift.org <mailto:swift-users at swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-users <https://lists.swift.org/mailman/listinfo/swift-users>
>>>
>>
>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
--
-Dave
More information about the swift-users
mailing list