I just stumbled upon this: Announcer subclass: #TxEditor .... This is just plain wrong, as wrong as: Shampoo subclass: #Shower because every time you treat inheritance as something else as _specialization_ you doing it wrong. Inheritance is not about importing needed functionality, it should be about specialization and only about it: - a superclass provides generic functionality, while subclasses providing more and more specialized forms of it. Because if we don't follow that, then it is really hard to see and follow a structure in design.. it is just random. And here's why: so since shower uses shampoo, as we concluded, then why not including it via inheritance: Shampoo subclass: #Shower but then, Shower also uses Soap, so maybe it should be like that: Soap subclass: #Shower so, which superclass you prefer most? And how do you pick/prioritize which element should be a superclass of Shower? To solve this dilemma, i think we will need multiple inheritance: (Shampoo, Soap) subclass: #Shower but thankfully, we don't have it in classic smalltalk model :) So, then maybe it should be something like that: Object subclass: #Shower instanceVariableNames: 'soap shampoo' ... Anyways, despite the obvious abuses, i'd like to ask community, in what cases , you think (ab)using inheritance in a way like above is justified? Because maybe it is i, who doing it wrong? -- Best regards, Igor Stasenko.
2013/7/19 Igor Stasenko <siguctua@gmail.com>
I just stumbled upon this:
Announcer subclass: #TxEditor ....
This is just plain wrong, as wrong as:
Shampoo subclass: #Shower
because every time you treat inheritance as something else as _specialization_ you doing it wrong. Inheritance is not about importing needed functionality, it should be about specialization and only about it:
Completely agree! If you inherit only because of reuse functionality, use traits instead :-) - a superclass provides generic functionality, while subclasses
providing more and more specialized forms of it.
Because if we don't follow that, then it is really hard to see and follow a structure in design.. it is just random.
And here's why:
so since shower uses shampoo, as we concluded, then why not including it via inheritance:
Shampoo subclass: #Shower
but then, Shower also uses Soap, so maybe it should be like that:
Soap subclass: #Shower
so, which superclass you prefer most? And how do you pick/prioritize which element should be a superclass of Shower?
To solve this dilemma, i think we will need multiple inheritance:
(Shampoo, Soap) subclass: #Shower
but thankfully, we don't have it in classic smalltalk model :)
So, then maybe it should be something like that:
Object subclass: #Shower instanceVariableNames: 'soap shampoo' ...
Anyways, despite the obvious abuses, i'd like to ask community, in what cases , you think (ab)using inheritance in a way like above is justified? Because maybe it is i, who doing it wrong?
-- Best regards, Igor Stasenko.
On 19 July 2013 15:48, Sebastian Tleye <stleye@gmail.com> wrote:
2013/7/19 Igor Stasenko <siguctua@gmail.com>
I just stumbled upon this:
Announcer subclass: #TxEditor ....
This is just plain wrong, as wrong as:
Shampoo subclass: #Shower
because every time you treat inheritance as something else as _specialization_ you doing it wrong. Inheritance is not about importing needed functionality, it should be about specialization and only about it:
Completely agree! If you inherit only because of reuse functionality, use traits instead :-)
Well, traits, i think, belong more to concern-oriented designs: when you wanna put handle concern in two (or more) different classes, which belong to different inheritance hierarchies. Else, this is just a poor-man's multiple inheritance. -- Best regards, Igor Stasenko.
Hi Igor, I love these discussions. I agree that abusing inheritance is counter-productive. Definitely, "Shampoo subclass: #Shower" does not match any mental model I can think of. But, I am not seeing "Announcer subclass: # MyDomainConcept" equally as an abuse. Here is why. When I say "Object subclass: #MyDomainConcept", my actual intention is not to reuse types necessarily, but rather the infrastructure needed for the Smalltalk runtime. From this point of view, it is an implementation inheritance. I could as well, inherit from ProtoObject, but I do not do it because Object gives me a bit more technical infrastructure. For me, Announcer is nothing but an Object that has an extra technical capability. Inheriting from Announcer rather than Object seems the same as inheriting from Object rather than ProtoObject. Now, you can shoot. Cheers, Doru On Fri, Jul 19, 2013 at 3:32 PM, Igor Stasenko <siguctua@gmail.com> wrote:
I just stumbled upon this:
Announcer subclass: #TxEditor ....
This is just plain wrong, as wrong as:
Shampoo subclass: #Shower
because every time you treat inheritance as something else as _specialization_ you doing it wrong. Inheritance is not about importing needed functionality, it should be about specialization and only about it: - a superclass provides generic functionality, while subclasses providing more and more specialized forms of it.
Because if we don't follow that, then it is really hard to see and follow a structure in design.. it is just random.
And here's why:
so since shower uses shampoo, as we concluded, then why not including it via inheritance:
Shampoo subclass: #Shower
but then, Shower also uses Soap, so maybe it should be like that:
Soap subclass: #Shower
so, which superclass you prefer most? And how do you pick/prioritize which element should be a superclass of Shower?
To solve this dilemma, i think we will need multiple inheritance:
(Shampoo, Soap) subclass: #Shower
but thankfully, we don't have it in classic smalltalk model :)
So, then maybe it should be something like that:
Object subclass: #Shower instanceVariableNames: 'soap shampoo' ...
Anyways, despite the obvious abuses, i'd like to ask community, in what cases , you think (ab)using inheritance in a way like above is justified? Because maybe it is i, who doing it wrong?
-- Best regards, Igor Stasenko.
-- www.tudorgirba.com "Every thing has its own flow"
On 19 July 2013 16:17, Tudor Girba <tudor@tudorgirba.com> wrote:
Hi Igor,
I love these discussions. I agree that abusing inheritance is counter-productive. Definitely, "Shampoo subclass: #Shower" does not match any mental model I can think of. But, I am not seeing "Announcer subclass: #MyDomainConcept" equally as an abuse.
Here is why.
When I say "Object subclass: #MyDomainConcept", my actual intention is not to reuse types necessarily, but rather the infrastructure needed for the Smalltalk runtime. From this point of view, it is an implementation inheritance. I could as well, inherit from ProtoObject, but I do not do it because Object gives me a bit more technical infrastructure.
For me, Announcer is nothing but an Object that has an extra technical capability. Inheriting from Announcer rather than Object seems the same as inheriting from Object rather than ProtoObject.
Now, you can shoot.
As i understood, you see nothing wrong in using inheritance as reuse, while i do. The argument with Object does not stands, to my thinking, because it is most generic class, and protocols it implements used by various parts of a system, including reflection etc, and those parts actually expecting that all objects they dealing with is at least implementing Object protocol(s). So, strictly speaking by inheriting from Object you may call it reuse, but to my thinking it is more about having a guarantee that your class will play well with the rest of smalltalk ecosystem (even if it's not your direct concern). While in case of inheriting from Announcer it is something different: you already have specific behavior which is non-universal for all objects in system (otherwise why not implementing Announcer protocol in Object?). Also, i am sure you aware, that by doing this, you introducing a certain degree of rigidness in your model (every time you refer directly to names instead of protocols, little kittie dies ;) because if today, Announcer serves well for your needs, and all is happy.. but maybe tomorrow, one guy will make a better one AnnouncerOnSteroids.. and to reuse it , you will need to change the parent in all numerous classes where you used Announcer originally. And to make it absolutely ridiculous, imagine how you will give user a choice whether use one Announcer or AnnouncerOnSteroids? You will recompile your classes each time? And what if parts of your model insist on using just Announcer while others having no problem with trying to play with AnnouncerOnSteroids? Another aspect of such abuse is when you inherit, you are tempted to use direct access to internal state and private methods, and that leads to really strange and complex problems later.. Just giving you an example: Suppose we have a class Butter, which implements #numberOfCalories and #fatPercentage protocols.. Now we do it like that: Butter subclass: #Fridge and then, of course fridge := Fridge new. fridge fatPercentage or: fridge fatPercentage: 10. ^^^ just look at the above line, how much sense you think this piece of code makes for reader, who will try to reason what is happens in your code? And why you think it is not the same story with Announcer? Because by subclassing from it, you expose its protocol(s) in places where it is not needed and will cause problems and confusion. Because when you inherit to reuse, not to specialize, then users of such class in most cases won't use full protocol of the superclass, nor require it.. and therefore by providing more than necessary, you are basically violating the principle of least authority. To fix that, you will need to override certain methods in your subclass to prevent exposing unwanted/low-level behavior to users. But that's again wrong, because then your model now starting to know too much about Announcer's internals, which should be an implementation detail, and adds even more rigidness to your design. -- Best regards, Igor Stasenko.
So, on your place, if you really need a lot of classes with announcer capabilities, you can do it like that: Object subclass: #ObjectWithAnnouncer instvars: 'announcer' then may implement same protocol as in Announcer in it, which will simply delegate to announcer ivar. And i bet, you don't want to expose full Announcer protocol there, while probably you may want to implement some convenience protocols, which Announcer lacking. So, at the end by subclassing from ObjectWithAnnouncer you will be reusing its capabilities in each and every subclass of it, but by delegating real job, you are free from worrying about dealing with implementation detail and exposing unwanted state/protocols to its users. Another aspect of it, is when i see: ObjectWithAnnouncer subclass: #MyDomainObject it tells me, aha.. so some (at least this one) of his domain objects having announcers, and the valid protocols is defined in ObjectWithAnnouncer. but when i see Announcer subclass: #MyDomainObject i starting to be uncertain: is Announcer private there or public? can i send messages like #basicSubscribe: to your domain object and expect that it will be handled correctly? Or do i allowed to subscribe directly at all, because maybe domain object has some specific protocol(s) and ways to do that.. Every such question and uncertainty for coder means more time, more errors, and less productivity. -- Best regards, Igor Stasenko.
Great answer Igor! I'm curious about Doru's response :) On 19.07.2013, at 17:31, Igor Stasenko <siguctua@gmail.com> wrote:
So, on your place, if you really need a lot of classes with announcer capabilities, you can do it like that:
Object subclass: #ObjectWithAnnouncer instvars: 'announcer'
then may implement same protocol as in Announcer in it, which will simply delegate to announcer ivar. And i bet, you don't want to expose full Announcer protocol there, while probably you may want to implement some convenience protocols, which Announcer lacking.
So, at the end by subclassing from ObjectWithAnnouncer you will be reusing its capabilities in each and every subclass of it, but by delegating real job, you are free from worrying about dealing with implementation detail and exposing unwanted state/protocols to its users.
Another aspect of it, is when i see:
ObjectWithAnnouncer subclass: #MyDomainObject
it tells me, aha.. so some (at least this one) of his domain objects having announcers, and the valid protocols is defined in ObjectWithAnnouncer.
but when i see
Announcer subclass: #MyDomainObject
i starting to be uncertain: is Announcer private there or public? can i send messages like #basicSubscribe: to your domain object and expect that it will be handled correctly? Or do i allowed to subscribe directly at all, because maybe domain object has some specific protocol(s) and ways to do that.. Every such question and uncertainty for coder means more time, more errors, and less productivity.
-- Best regards, Igor Stasenko.
Hi 2013/7/19 Igor Stasenko <siguctua@gmail.com>
So, on your place, if you really need a lot of classes with announcer capabilities, you can do it like that:
Object subclass: #ObjectWithAnnouncer instvars: 'announcer'
ObjectWithAnnouncer is exactly what I think about Announcer. I just need class which makes my objects events sources. And I'm wondering why Announcer is bad for this? Just look at Announcer definition: Object subclass: #Announcer instanceVariableNames: 'registry' classVariableNames: '' poolDictionaries: '' category: 'Announcements-Core' "registry" variable is instance of SubscriptionsRegistry which actually implements all announcements logic. Announcer just adds convenient public api to events subscriptions and delivering. No complex logic. No actual knowledge about how announcements work. And your argument "why you subclass from Announcer" looks to me like why you subclass from SubscriptionsRegistry. But I'm not. Nobody doing it. So i'm not understand why you want another wrapper around Announcer. (To me "subscriptions" is better name then "registry". And I prefer composition than inheritance too).
then may implement same protocol as in Announcer in it, which will simply delegate to announcer ivar. And i bet, you don't want to expose full Announcer protocol there, while probably you may want to implement some convenience protocols, which Announcer lacking.
So, at the end by subclassing from ObjectWithAnnouncer you will be reusing its capabilities in each and every subclass of it, but by delegating real job, you are free from worrying about dealing with implementation detail and exposing unwanted state/protocols to its users.
Another aspect of it, is when i see:
ObjectWithAnnouncer subclass: #MyDomainObject
it tells me, aha.. so some (at least this one) of his domain objects having announcers, and the valid protocols is defined in ObjectWithAnnouncer.
but when i see
Announcer subclass: #MyDomainObject
i starting to be uncertain: is Announcer private there or public? can i send messages like #basicSubscribe: to your domain object and expect that it will be handled correctly? Or do i allowed to subscribe directly at all, because maybe domain object has some specific protocol(s) and ways to do that.. Every such question and uncertainty for coder means more time, more errors, and less productivity.
-- Best regards, Igor Stasenko.
How about statefull Traits? http://scg.unibe.ch/archive/papers/Berg07aStatefulTraits.pdf On 2013-07-20, at 12:48, Denis Kudriashov <dionisiydk@gmail.com> wrote:
Hi
2013/7/19 Igor Stasenko <siguctua@gmail.com>
So, on your place, if you really need a lot of classes with announcer capabilities, you can do it like that:
Object subclass: #ObjectWithAnnouncer instvars: 'announcer'
ObjectWithAnnouncer is exactly what I think about Announcer. I just need class which makes my objects events sources. And I'm wondering why Announcer is bad for this? Just look at Announcer definition:
Object subclass: #Announcer
instanceVariableNames: 'registry'
classVariableNames: ''
poolDictionaries: ''
category: 'Announcements-Core'
"registry" variable is instance of SubscriptionsRegistry which actually implements all announcements logic. Announcer just adds convenient public api to events subscriptions and delivering. No complex logic. No actual knowledge about how announcements work. And your argument "why you subclass from Announcer" looks to me like why you subclass from SubscriptionsRegistry. But I'm not. Nobody doing it. So i'm not understand why you want another wrapper around Announcer.
(To me "subscriptions" is better name then "registry". And I prefer composition than inheritance too).
then may implement same protocol as in Announcer in it, which will simply delegate to announcer ivar. And i bet, you don't want to expose full Announcer protocol there, while probably you may want to implement some convenience protocols, which Announcer lacking.
So, at the end by subclassing from ObjectWithAnnouncer you will be reusing its capabilities in each and every subclass of it, but by delegating real job, you are free from worrying about dealing with implementation detail and exposing unwanted state/protocols to its users.
Another aspect of it, is when i see:
ObjectWithAnnouncer subclass: #MyDomainObject
it tells me, aha.. so some (at least this one) of his domain objects having announcers, and the valid protocols is defined in ObjectWithAnnouncer.
but when i see
Announcer subclass: #MyDomainObject
i starting to be uncertain: is Announcer private there or public? can i send messages like #basicSubscribe: to your domain object and expect that it will be handled correctly? Or do i allowed to subscribe directly at all, because maybe domain object has some specific protocol(s) and ways to do that.. Every such question and uncertainty for coder means more time, more errors, and less productivity.
-- Best regards, Igor Stasenko.
Certainly :) Doru On Sat, Jul 20, 2013 at 1:48 PM, Camillo Bruni <camillobruni@gmail.com>wrote:
How about statefull Traits? http://scg.unibe.ch/archive/papers/Berg07aStatefulTraits.pdf
On 2013-07-20, at 12:48, Denis Kudriashov <dionisiydk@gmail.com> wrote:
Hi
2013/7/19 Igor Stasenko <siguctua@gmail.com>
So, on your place, if you really need a lot of classes with announcer capabilities, you can do it like that:
Object subclass: #ObjectWithAnnouncer instvars: 'announcer'
ObjectWithAnnouncer is exactly what I think about Announcer. I just need class which makes my objects events sources. And I'm wondering why Announcer is bad for this? Just look at Announcer definition:
Object subclass: #Announcer
instanceVariableNames: 'registry'
classVariableNames: ''
poolDictionaries: ''
category: 'Announcements-Core'
"registry" variable is instance of SubscriptionsRegistry which actually implements all announcements logic. Announcer just adds convenient public api to events subscriptions and delivering. No complex logic. No actual knowledge about how announcements work. And your argument "why you subclass from Announcer" looks to me like why you subclass from SubscriptionsRegistry. But I'm not. Nobody doing it. So i'm not understand why you want another wrapper around Announcer.
(To me "subscriptions" is better name then "registry". And I prefer composition than inheritance too).
then may implement same protocol as in Announcer in it, which will simply delegate to announcer ivar. And i bet, you don't want to expose full Announcer protocol there, while probably you may want to implement some convenience protocols, which Announcer lacking.
So, at the end by subclassing from ObjectWithAnnouncer you will be reusing its capabilities in each and every subclass of it, but by delegating real job, you are free from worrying about dealing with implementation detail and exposing unwanted state/protocols to its users.
Another aspect of it, is when i see:
ObjectWithAnnouncer subclass: #MyDomainObject
it tells me, aha.. so some (at least this one) of his domain objects having announcers, and the valid protocols is defined in ObjectWithAnnouncer.
but when i see
Announcer subclass: #MyDomainObject
i starting to be uncertain: is Announcer private there or public? can i send messages like #basicSubscribe: to your domain object and expect that it will be handled correctly? Or do i allowed to subscribe directly at all, because maybe domain object has some specific protocol(s) and ways to do that.. Every such question and uncertainty for coder means more time, more errors, and less productivity.
-- Best regards, Igor Stasenko.
-- www.tudorgirba.com "Every thing has its own flow"
On 20 July 2013 12:48, Denis Kudriashov <dionisiydk@gmail.com> wrote:
Hi
2013/7/19 Igor Stasenko <siguctua@gmail.com>
So, on your place, if you really need a lot of classes with announcer capabilities, you can do it like that:
Object subclass: #ObjectWithAnnouncer instvars: 'announcer'
ObjectWithAnnouncer is exactly what I think about Announcer. I just need class which makes my objects events sources. And I'm wondering why Announcer is bad for this? Just look at Announcer definition:
Object subclass: #Announcer
instanceVariableNames: 'registry'
classVariableNames: ''
poolDictionaries: ''
category: 'Announcements-Core'
"registry" variable is instance of SubscriptionsRegistry which actually implements all announcements logic. Announcer just adds convenient public api to events subscriptions and delivering. No complex logic. No actual knowledge about how announcements work. And your argument "why you subclass from Announcer" looks to me like why you subclass from SubscriptionsRegistry. But I'm not. Nobody doing it. So i'm not understand why you want another wrapper around Announcer.
(To me "subscriptions" is better name then "registry". And I prefer composition than inheritance too).
There are 3 kinds of roles in context: - subscriber: an object who subscribing for events to receive them later - an event source (the object which announces the event) - an announcer, an object which provides subscription service and through which you can announce events, acting as mediator between 2 parties above the rest, like registry, Announcement (as class) and subscriptions is implementation detail. The main reason for using Announcements model is to have decoupling between event source (the place/object , which producing events) and its handlers. And announcer provides such decoupling. That means, both subscribers and event source(s) don't need to have direct knowledge about each other, all they need is to use same announcer to establish communication channel. Then, subscribers don't really care who triggered an event and why/where while event source don't really cares who will handle the event(s), in what order or how many of them there. Now, what happens when you mixing roles and treating announcer as an event source? (and by subclassing from Announcer you doing that). When you merge event source and announcer, then your subscribers are forced to have direct access to event source, and that means you actually not using/need decoupling at all. In this regard, my question: why then you using Announcements model at all? Because it is there, or because there should be only one? I don't think that either of these reasons are valid. When you don't need decoupling , i do not see much value in using Announcements. I would implement/use something else then. -- Best regards, Igor Stasenko.
Hi Igor. 2013/7/21 Igor Stasenko <siguctua@gmail.com>
There are 3 kinds of roles in context:
- subscriber: an object who subscribing for events to receive them later - an event source (the object which announces the event) - an announcer, an object which provides subscription service and through which you can announce events, acting as mediator between 2 parties above
the rest, like registry, Announcement (as class) and subscriptions is implementation detail. The main reason for using Announcements model is to have decoupling between event source (the place/object , which producing events) and its handlers. And announcer provides such decoupling.
I understand your position. But I think it is too little and simple place to introduce another object. And original paper about Announcements framework (maybe from Vasiliy Bykov) not described such distinction between event source and announcer as subscription service. Too me subscription service is exactly SubscriptionsRegistry. Interesting how Announcer used in VisualWorks system. Any way if we agree with your proposals we should add EventsSource class (choose better name) to Announcements package. And we should describe it in announcements chapter in pharo book. Because now there are no documentation where your distinction are explained and that's why now natural way to make event source classes is subclassing Announcer. Best regards, Denis
On 7/19/13, Igor Stasenko <siguctua@gmail.com> wrote:
On 19 July 2013 16:17, Tudor Girba <tudor@tudorgirba.com> wrote:
Hi Igor,
I love these discussions. I agree that abusing inheritance is counter-productive. Definitely, "Shampoo subclass: #Shower" does not match any mental model I can think of. But, I am not seeing "Announcer subclass: #MyDomainConcept" equally as an abuse.
Here is why.
When I say "Object subclass: #MyDomainConcept", my actual intention is not to reuse types necessarily, but rather the infrastructure needed for the Smalltalk runtime. From this point of view, it is an implementation inheritance. I could as well, inherit from ProtoObject, but I do not do it because Object gives me a bit more technical infrastructure.
For me, Announcer is nothing but an Object that has an extra technical capability. Inheriting from Announcer rather than Object seems the same as inheriting from Object rather than ProtoObject.
Now, you can shoot.
As i understood, you see nothing wrong in using inheritance as reuse, while i do.
not generally I assume Tudor thinks, only for this particular case of sub classing Announcer. Announcing behaviour may be considered part of a package objects should have and this has been the case in Smalltalk since the beginning, though implemented with the symbol based changed/update mechanism. To restate Yes, I agree that subclasses should specialize the behaviour of the superclass. But there need to be classes first you may subclass to specialize and these inherit general properties of object behaviour. --Hannes
The argument with Object does not stands, to my thinking, because it is most generic class, and protocols it implements used by various parts of a system, including reflection etc, and those parts actually expecting that all objects they dealing with is at least implementing Object protocol(s). So, strictly speaking by inheriting from Object you may call it reuse, but to my thinking it is more about having a guarantee that your class will play well with the rest of smalltalk ecosystem (even if it's not your direct concern).
While in case of inheriting from Announcer it is something different: you already have specific behavior which is non-universal for all objects in system (otherwise why not implementing Announcer protocol in Object?).
Also, i am sure you aware, that by doing this, you introducing a certain degree of rigidness in your model (every time you refer directly to names instead of protocols, little kittie dies ;)
because if today, Announcer serves well for your needs, and all is happy.. but maybe tomorrow, one guy will make a better one AnnouncerOnSteroids.. and to reuse it , you will need to change the parent in all numerous classes where you used Announcer originally. And to make it absolutely ridiculous, imagine how you will give user a choice whether use one Announcer or AnnouncerOnSteroids? You will recompile your classes each time? And what if parts of your model insist on using just Announcer while others having no problem with trying to play with AnnouncerOnSteroids?
Another aspect of such abuse is when you inherit, you are tempted to use direct access to internal state and private methods, and that leads to really strange and complex problems later..
Just giving you an example:
Suppose we have a class Butter, which implements #numberOfCalories and #fatPercentage protocols..
Now we do it like that:
Butter subclass: #Fridge
and then, of course
fridge := Fridge new.
fridge fatPercentage
or:
fridge fatPercentage: 10.
^^^ just look at the above line, how much sense you think this piece of code makes for reader, who will try to reason what is happens in your code?
And why you think it is not the same story with Announcer?
Because by subclassing from it, you expose its protocol(s) in places where it is not needed and will cause problems and confusion. Because when you inherit to reuse, not to specialize, then users of such class in most cases won't use full protocol of the superclass, nor require it.. and therefore by providing more than necessary, you are basically violating the principle of least authority. To fix that, you will need to override certain methods in your subclass to prevent exposing unwanted/low-level behavior to users. But that's again wrong, because then your model now starting to know too much about Announcer's internals, which should be an implementation detail, and adds even more rigidness to your design.
-- Best regards, Igor Stasenko.
Thanks, Hannes. I am not completely misunderstood, then :) Doru On Sat, Jul 20, 2013 at 2:02 PM, H. Hirzel <hannes.hirzel@gmail.com> wrote:
On 7/19/13, Igor Stasenko <siguctua@gmail.com> wrote:
On 19 July 2013 16:17, Tudor Girba <tudor@tudorgirba.com> wrote:
Hi Igor,
I love these discussions. I agree that abusing inheritance is counter-productive. Definitely, "Shampoo subclass: #Shower" does not match any mental model I can think of. But, I am not seeing "Announcer subclass: #MyDomainConcept" equally as an abuse.
Here is why.
When I say "Object subclass: #MyDomainConcept", my actual intention is not to reuse types necessarily, but rather the infrastructure needed for the Smalltalk runtime. From this point of view, it is an implementation inheritance. I could as well, inherit from ProtoObject, but I do not do it because Object gives me a bit more technical infrastructure.
For me, Announcer is nothing but an Object that has an extra technical capability. Inheriting from Announcer rather than Object seems the same as inheriting from Object rather than ProtoObject.
Now, you can shoot.
As i understood, you see nothing wrong in using inheritance as reuse, while i do.
not generally I assume Tudor thinks, only for this particular case of sub classing Announcer. Announcing behaviour may be considered part of a package objects should have and this has been the case in Smalltalk since the beginning, though implemented with the symbol based changed/update mechanism.
To restate Yes, I agree that subclasses should specialize the behaviour of the superclass. But there need to be classes first you may subclass to specialize and these inherit general properties of object behaviour.
--Hannes
The argument with Object does not stands, to my thinking, because it is most generic class, and protocols it implements used by various parts of a system, including reflection etc, and those parts actually expecting that all objects they dealing with is at least implementing Object protocol(s). So, strictly speaking by inheriting from Object you may call it reuse, but to my thinking it is more about having a guarantee that your class will play well with the rest of smalltalk ecosystem (even if it's not your direct concern).
While in case of inheriting from Announcer it is something different: you already have specific behavior which is non-universal for all objects in system (otherwise why not implementing Announcer protocol in Object?).
Also, i am sure you aware, that by doing this, you introducing a certain degree of rigidness in your model (every time you refer directly to names instead of protocols, little kittie dies ;)
because if today, Announcer serves well for your needs, and all is happy.. but maybe tomorrow, one guy will make a better one AnnouncerOnSteroids.. and to reuse it , you will need to change the parent in all numerous classes where you used Announcer originally. And to make it absolutely ridiculous, imagine how you will give user a choice whether use one Announcer or AnnouncerOnSteroids? You will recompile your classes each time? And what if parts of your model insist on using just Announcer while others having no problem with trying to play with AnnouncerOnSteroids?
Another aspect of such abuse is when you inherit, you are tempted to use direct access to internal state and private methods, and that leads to really strange and complex problems later..
Just giving you an example:
Suppose we have a class Butter, which implements #numberOfCalories and #fatPercentage protocols..
Now we do it like that:
Butter subclass: #Fridge
and then, of course
fridge := Fridge new.
fridge fatPercentage
or:
fridge fatPercentage: 10.
^^^ just look at the above line, how much sense you think this piece of code makes for reader, who will try to reason what is happens in your code?
And why you think it is not the same story with Announcer?
Because by subclassing from it, you expose its protocol(s) in places where it is not needed and will cause problems and confusion. Because when you inherit to reuse, not to specialize, then users of such class in most cases won't use full protocol of the superclass, nor require it.. and therefore by providing more than necessary, you are basically violating the principle of least authority. To fix that, you will need to override certain methods in your subclass to prevent exposing unwanted/low-level behavior to users. But that's again wrong, because then your model now starting to know too much about Announcer's internals, which should be an implementation detail, and adds even more rigidness to your design.
-- Best regards, Igor Stasenko.
-- www.tudorgirba.com "Every thing has its own flow"
Hi Igor, Thanks for taking the time to write such a long answer. I think you misunderstood my point :). I simply said that the two examples are not the same (and I can add now that "Butter subclass: #Fridge" is as bad as "Shampoo subclass: #Shower", but they are both different from "Announcer subclass: #MyDomainConcept"). As I understand, you conceded the point that inheriting from Object has reuse reasons, but that it is so because Object provides generic mechanisms that everyone wants. I can imagine scenarios where I want a different reflection support. All of a sudden the generic mechanism is not so generic anymore, and you get in the same situation as the one of wanting a different Announcer kind. Does it mean that inheriting from Object is a bad thing? No. It is a great good enough compromise for 99.9% of the cases. Then you say that Announcer is not in the Object protocol as if this would be necessarily a good thing. I can argue that every Object should have announcer capabilities just like it has exception handling capabilities, but then we would go even further away from the main point :). Inheritance as reuse is definitely to be avoided, and indeed the principle of Least Authority (or more known as Principle of Least Privilege) is a relevant point (I concede that :)). However, I guess you agree that having #class defined in Object is not a horrible (it can be better, but it is not horrible) thing even if most objects do not need this information. Another principle that might be more useful when thinking about inheritance is the Liskov Substitution Principle. From this point of view, as long as MyDomainConcept does not redefine the meaning of Announcer, it is not unreasonable to have it inherit from Announcer. I stop now. You can continue to shoot :). Cheers, Doru On Fri, Jul 19, 2013 at 4:54 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 19 July 2013 16:17, Tudor Girba <tudor@tudorgirba.com> wrote:
Hi Igor,
I love these discussions. I agree that abusing inheritance is counter-productive. Definitely, "Shampoo subclass: #Shower" does not match any mental model I can think of. But, I am not seeing "Announcer subclass: #MyDomainConcept" equally as an abuse.
Here is why.
When I say "Object subclass: #MyDomainConcept", my actual intention is not to reuse types necessarily, but rather the infrastructure needed for the Smalltalk runtime. From this point of view, it is an implementation inheritance. I could as well, inherit from ProtoObject, but I do not do it because Object gives me a bit more technical infrastructure.
For me, Announcer is nothing but an Object that has an extra technical capability. Inheriting from Announcer rather than Object seems the same as inheriting from Object rather than ProtoObject.
Now, you can shoot.
As i understood, you see nothing wrong in using inheritance as reuse, while i do.
The argument with Object does not stands, to my thinking, because
it is most generic class, and protocols it implements used by various parts of a system, including reflection etc, and those parts actually expecting that all objects they dealing with is at least implementing Object protocol(s). So, strictly speaking by inheriting from Object you may call it reuse, but to my thinking it is more about having a guarantee that your class will play well with the rest of smalltalk ecosystem (even if it's not your direct concern).
While in case of inheriting from Announcer it is something different: you already have specific behavior which is non-universal for all objects in system (otherwise why not implementing Announcer protocol in Object?).
Also, i am sure you aware, that by doing this, you introducing a certain degree of rigidness in your model (every time you refer directly to names instead of protocols, little kittie dies ;)
because if today, Announcer serves well for your needs, and all is happy.. but maybe tomorrow, one guy will make a better one AnnouncerOnSteroids.. and to reuse it , you will need to change the parent in all numerous classes where you used Announcer originally. And to make it absolutely ridiculous, imagine how you will give user a choice whether use one Announcer or AnnouncerOnSteroids? You will recompile your classes each time? And what if parts of your model insist on using just Announcer while others having no problem with trying to play with AnnouncerOnSteroids?
Another aspect of such abuse is when you inherit, you are tempted to use direct access to internal state and private methods, and that leads to really strange and complex problems later..
Just giving you an example:
Suppose we have a class Butter, which implements #numberOfCalories and #fatPercentage protocols..
Now we do it like that:
Butter subclass: #Fridge
and then, of course
fridge := Fridge new.
fridge fatPercentage
or:
fridge fatPercentage: 10.
^^^ just look at the above line, how much sense you think this piece of code makes for reader, who will try to reason what is happens in your code?
And why you think it is not the same story with Announcer?
Because by subclassing from it, you expose its protocol(s) in places where it is not needed and will cause problems and confusion. Because when you inherit to reuse, not to specialize, then users of such class in most cases won't use full protocol of the superclass, nor require it.. and therefore by providing more than necessary, you are basically violating the principle of least authority. To fix that, you will need to override certain methods in your subclass to prevent exposing unwanted/low-level behavior to users. But that's again wrong, because then your model now starting to know too much about Announcer's internals, which should be an implementation detail, and adds even more rigidness to your design.
-- Best regards, Igor Stasenko.
-- www.tudorgirba.com "Every thing has its own flow"
On 20 July 2013 21:31, Tudor Girba <tudor@tudorgirba.com> wrote:
Hi Igor,
Thanks for taking the time to write such a long answer.
I think you misunderstood my point :). I simply said that the two examples are not the same (and I can add now that "Butter subclass: #Fridge" is as bad as "Shampoo subclass: #Shower", but they are both different from "Announcer subclass: #MyDomainConcept").
It is only in your mind. If someone else will look at your code, he won't make any difference (and you can tell me why ;). And that is what matters. You know, i can also (ab)use things in my code and make very strange things, which can be understood only by me.. depending on intent, like having highly optimized code or as a way to code less (making many subclasses can be tiresome sometimes ;) But if there's any chance that anyone else will use this code or will need to change/understand/improve it, i would not do that. Because when i do, i putting them into misery.
As I understand, you conceded the point that inheriting from Object has reuse reasons, but that it is so because Object provides generic mechanisms that everyone wants. I can imagine scenarios where I want a different reflection support. All of a sudden the generic mechanism is not so generic anymore, and you get in the same situation as the one of wanting a different Announcer kind. Does it mean that inheriting from Object is a bad thing? No. It is a great good enough compromise for 99.9% of the cases.
Then you say that Announcer is not in the Object protocol as if this would be necessarily a good thing. I can argue that every Object should have announcer capabilities just like it has exception handling capabilities, but then we would go even further away from the main point :).
Not at all, i also think that having a generic way for any object to act as event source is quite valuable. That's why, there is already existing protocols for that (see events-blah categories). And dependents mechanism. And that's why we want to eventually unify them.. because there's too many.
Inheritance as reuse is definitely to be avoided, and indeed the principle of Least Authority (or more known as Principle of Least Privilege) is a relevant point (I concede that :)). However, I guess you agree that having #class defined in Object is not a horrible (it can be better, but it is not horrible) thing even if most objects do not need this information.
Another principle that might be more useful when thinking about inheritance is the Liskov Substitution Principle. From this point of view, as long as MyDomainConcept does not redefine the meaning of Announcer, it is not unreasonable to have it inherit from Announcer.
Yes, but where are the guarantees that you don't? Just think from outsider's point of view: when he sees Announcer subclass: #Foo what he will think first: - aha, this guy implements own kind of announcer or - aha this guy reusing announcer or - aha, this guy doing both things at the same time (a worst possible alternative) and how many abuses like that, he should see before making a logical conclusion: - aha.. this is the way how i should do as well.
I stop now. You can continue to shoot :).
-- Best regards, Igor Stasenko.
On Jul 21, 2013, at 2:38 PM, Igor Stasenko <siguctua@gmail.com> wrote:
Yes, but where are the guarantees that you don't? Just think from outsider's point of view: when he sees
Announcer subclass: #Foo
what he will think first: - aha, this guy implements own kind of announcer or - aha this guy reusing announcer
+ 1 Stef
2013/7/21 Igor Stasenko <siguctua@gmail.com>
Yes, but where are the guarantees that you don't? Just think from outsider's point of view: when he sees
Announcer subclass: #Foo
what he will think first: - aha, this guy implements own kind of announcer or - aha this guy reusing announcer or - aha, this guy doing both things at the same time (a worst possible alternative)
and how many abuses like that, he should see before making a logical conclusion: - aha.. this is the way how i should do as well.
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor? Because to me it is not practical design issues when we talk about subclassing Announcer.
On Jul 21, 2013, at 5:36 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2013/7/21 Igor Stasenko <siguctua@gmail.com> Yes, but where are the guarantees that you don't? Just think from outsider's point of view: when he sees
Announcer subclass: #Foo
what he will think first: - aha, this guy implements own kind of announcer or - aha this guy reusing announcer or - aha, this guy doing both things at the same time (a worst possible alternative)
and how many abuses like that, he should see before making a logical conclusion: - aha.. this is the way how i should do as well.
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor?
Many this is composition using inheritance and inheritance should not be used like that. Announcer subclass: #GreedyAnnouncer Announcer subclass: #RemoteAnnouncer Are quite different from Announcer subclass: #Customer This is not because subclassing can be used that we should do it. We suffer during years from Dictionary subclass: #Set and other beauties.
Because to me it is not practical design issues when we talk about subclassing Announcer.
Though, Dictionary was technically a Set of Associations, until someone changed Association>>= to also compare values. 2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
On Jul 21, 2013, at 5:36 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2013/7/21 Igor Stasenko <siguctua@gmail.com>
Yes, but where are the guarantees that you don't? Just think from outsider's point of view: when he sees
Announcer subclass: #Foo
what he will think first: - aha, this guy implements own kind of announcer or - aha this guy reusing announcer or - aha, this guy doing both things at the same time (a worst possible alternative)
and how many abuses like that, he should see before making a logical conclusion: - aha.. this is the way how i should do as well.
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor?
Many this is composition using inheritance and inheritance should not be used like that.
Announcer subclass: #GreedyAnnouncer
Announcer subclass: #RemoteAnnouncer
Are quite different from Announcer subclass: #Customer
This is not because subclassing can be used that we should do it. We suffer during years from Dictionary subclass: #Set and other beauties.
Because to me it is not practical design issues when we talk about subclassing Announcer.
On Jul 21, 2013, at 7:30 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Though, Dictionary was technically a Set of Associations,
yes but API(DICTIONARY) is not the same as API(SET) => ARGHHHHHHHHHHHHHHHHH
until someone changed Association>>= to also compare values.
subclassing does not mean that technically it is wrong. subclassing is reuse so reuse is happening but at the cost of bending APIs and killing the poor maintainers with yyy ^ super xxx and should not understand. Stef
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
On Jul 21, 2013, at 5:36 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2013/7/21 Igor Stasenko <siguctua@gmail.com> Yes, but where are the guarantees that you don't? Just think from outsider's point of view: when he sees
Announcer subclass: #Foo
what he will think first: - aha, this guy implements own kind of announcer or - aha this guy reusing announcer or - aha, this guy doing both things at the same time (a worst possible alternative)
and how many abuses like that, he should see before making a logical conclusion: - aha.. this is the way how i should do as well.
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor?
Many this is composition using inheritance and inheritance should not be used like that.
Announcer subclass: #GreedyAnnouncer
Announcer subclass: #RemoteAnnouncer
Are quite different from
Announcer subclass: #Customer
This is not because subclassing can be used that we should do it. We suffer during years from Dictionary subclass: #Set and other beauties.
Because to me it is not practical design issues when we talk about subclassing Announcer.
Of course, Dictionary was somehow a Set, but somehow behaved more like a Bag (it could be seen as a Bag of values w.r.t. #do: behavior),. But we still solved it with inheritance, just with an intermediate HashedCollection capturing common abstract behavior... 2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
On Jul 21, 2013, at 7:30 PM, Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com> wrote:
Though, Dictionary was technically a Set of Associations,
yes but API(DICTIONARY) is not the same as API(SET) => ARGHHHHHHHHHHHHHHHHH
until someone changed Association>>= to also compare values.
subclassing does not mean that technically it is wrong. subclassing is reuse so reuse is happening but at the cost of bending APIs and killing the poor maintainers with yyy ^ super xxx and should not understand.
Stef
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
On Jul 21, 2013, at 5:36 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2013/7/21 Igor Stasenko <siguctua@gmail.com>
Yes, but where are the guarantees that you don't? Just think from outsider's point of view: when he sees
Announcer subclass: #Foo
what he will think first: - aha, this guy implements own kind of announcer or - aha this guy reusing announcer or - aha, this guy doing both things at the same time (a worst possible alternative)
and how many abuses like that, he should see before making a logical conclusion: - aha.. this is the way how i should do as well.
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor?
Many this is composition using inheritance and inheritance should not be used like that.
Announcer subclass: #GreedyAnnouncer
Announcer subclass: #RemoteAnnouncer
Are quite different from Announcer subclass: #Customer
This is not because subclassing can be used that we should do it. We suffer during years from Dictionary subclass: #Set and other beauties.
Because to me it is not practical design issues when we talk about subclassing Announcer.
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor?
Many this is composition using inheritance and inheritance should not be used like that.
Announcer subclass: #GreedyAnnouncer
Announcer subclass: #RemoteAnnouncer
And if we prefer composition we should not implement such kind of hierarchy. We should implement GreadySubscriptionsRegistry, RemoteSubscriptionsRegistry or AsynchSubscriptionsRegistry and reuse existed Announcer. All subscribing and delivering logic implemented by subscription registry. Announcer is just simple delegator with convenient api to create Subscription instances: Announcer>>subscribe: anAnnouncementClass do: aValuable "Declare that when anAnnouncementClass is raised, aValuable is executed." ^ registry add: ( AnnouncementSubscription new announcer: self; announcementClass: anAnnouncementClass; valuable: aValuable) Announcer>>announce: anAnnouncement | announcement | announcement := anAnnouncement asAnnouncement. registry ifNotNil: [ registry deliver: announcement ]. ^ announcement All magic happens inside #add: and #deliver: methods of SubscriptionsRegistry. Also announcements framework provides very nice feature: you can have announcer as last argument of event handler selector (that's why AnnouncementSubscription contains reference to announcer instance): announcer on: MyEvent send: #handleAnnouncement:raisedBy: to: aSubscriber Without subclassing YourEventsSource from Announcer you will not have such feature. Or you will need implement complex subscription method inside YourEventSource which will delegates special event handler to its announcer
On 21 July 2013 20:21, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor?
Many this is composition using inheritance and inheritance should not be used like that.
Announcer subclass: #GreedyAnnouncer
Announcer subclass: #RemoteAnnouncer
And if we prefer composition we should not implement such kind of hierarchy. We should implement GreadySubscriptionsRegistry, RemoteSubscriptionsRegistry or AsynchSubscriptionsRegistry and reuse existed Announcer. All subscribing and delivering logic implemented by subscription registry. Announcer is just simple delegator with convenient api to create Subscription instances:
Announcer>>subscribe: anAnnouncementClass do: aValuable "Declare that when anAnnouncementClass is raised, aValuable is executed." ^ registry add: ( AnnouncementSubscription new announcer: self; announcementClass: anAnnouncementClass; valuable: aValuable)
Announcer>>announce: anAnnouncement
| announcement | announcement := anAnnouncement asAnnouncement. registry ifNotNil: [ registry deliver: announcement ]. ^ announcement
All magic happens inside #add: and #deliver: methods of SubscriptionsRegistry.
Also announcements framework provides very nice feature: you can have announcer as last argument of event handler selector (that's why AnnouncementSubscription contains reference to announcer instance):
announcer on: MyEvent send: #handleAnnouncement:raisedBy: to: aSubscriber
Without subclassing YourEventsSource from Announcer you will not have such feature. Or you will need implement complex subscription method inside YourEventSource which will delegates special event handler to its announcer
1. you don't need separate class to represent event source. it can be any object which does: announcer announce: Foo. in any place.. I do not see any practical gains from forming a separate class for this role. It is barely formalizeable because the way how users creating and triggering events is arbitrary. 2. SubscriptionRegistry is an implementation detail. It is private. It is a way how Announcer doing things inside. It should be no concern of anything outside to consider what it does. You won't find this class in VisualWorks implementation, for instance. 3. again, event source - is any object which says 'announcer announce: ...' It is NOT announcer, because announcer is an event dispatcher. dispatcher ~= source Is it so hard to see a difference? When you subclass from Announcer, is that you want to say: 'self announce:' , so the very same object acts both as event source and event dispatcher. But then , as Stef said, by subclassing you inheriting API. So, what prevents me from writing following code, in my own class, which uses your domain object in a following way: coolDomainObject := YourDomainObjectWhichInheritsFromAnnouncer new. coolDomainObject on: Foo do: #bar. coolDomainObject announce: Foo. That i guess is not something you expected, huh? But why not? As long as your object understand this protocol, and as long as you don't overriding original behavior of Announcer, i can abuse your object in a way you did not expected. And this is a consequence of violating principle of least authority. Because once you declare that we're free to use subclassing for any purpose, then, i can declare: i am free to use any subclass of Announcer as announcer for myself. Lets write random code, do not follow any rules and everyone will be happy. --- Best regards, Igor Stasenko.
I love this debate, but given the energy it attracted, I now apologize to have fueled it. By reading the thread, I believe that everyone involved in the discussion is on the same page on 99.9% of the cases, the only real difference being the case of the Announcer (and even there, the difference is more philosophical in nature). Would it be Ok to call it a day and move on? :) Cheers, Doru On Mon, Jul 22, 2013 at 1:05 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 21 July 2013 20:21, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor?
Many this is composition using inheritance and inheritance should not be used like that.
Announcer subclass: #GreedyAnnouncer
Announcer subclass: #RemoteAnnouncer
And if we prefer composition we should not implement such kind of hierarchy. We should implement GreadySubscriptionsRegistry, RemoteSubscriptionsRegistry or AsynchSubscriptionsRegistry and reuse existed Announcer. All subscribing and delivering logic implemented by subscription registry. Announcer is just simple delegator with convenient api to create Subscription instances:
Announcer>>subscribe: anAnnouncementClass do: aValuable "Declare that when anAnnouncementClass is raised, aValuable is executed." ^ registry add: ( AnnouncementSubscription new announcer: self; announcementClass: anAnnouncementClass; valuable: aValuable)
Announcer>>announce: anAnnouncement
| announcement | announcement := anAnnouncement asAnnouncement. registry ifNotNil: [ registry deliver: announcement ]. ^ announcement
All magic happens inside #add: and #deliver: methods of SubscriptionsRegistry.
Also announcements framework provides very nice feature: you can have announcer as last argument of event handler selector (that's why AnnouncementSubscription contains reference to announcer instance):
announcer on: MyEvent send: #handleAnnouncement:raisedBy: to: aSubscriber
Without subclassing YourEventsSource from Announcer you will not have such feature. Or you will need implement complex subscription method inside YourEventSource which will delegates special event handler to its announcer
1. you don't need separate class to represent event source. it can be any object which does:
announcer announce: Foo.
in any place.. I do not see any practical gains from forming a separate class for this role. It is barely formalizeable because the way how users creating and triggering events is arbitrary.
2. SubscriptionRegistry is an implementation detail. It is private. It is a way how Announcer doing things inside. It should be no concern of anything outside to consider what it does. You won't find this class in VisualWorks implementation, for instance.
3. again, event source - is any object which says 'announcer announce: ...' It is NOT announcer, because announcer is an event dispatcher. dispatcher ~= source Is it so hard to see a difference?
When you subclass from Announcer, is that you want to say:
'self announce:' , so the very same object acts both as event source and event dispatcher.
But then , as Stef said, by subclassing you inheriting API. So, what prevents me from writing following code, in my own class, which uses your domain object in a following way:
coolDomainObject := YourDomainObjectWhichInheritsFromAnnouncer new.
coolDomainObject on: Foo do: #bar. coolDomainObject announce: Foo.
That i guess is not something you expected, huh? But why not? As long as your object understand this protocol, and as long as you don't overriding original behavior of Announcer, i can abuse your object in a way you did not expected. And this is a consequence of violating principle of least authority.
Because once you declare that we're free to use subclassing for any purpose, then, i can declare: i am free to use any subclass of Announcer as announcer for myself.
Lets write random code, do not follow any rules and everyone will be happy.
--- Best regards, Igor Stasenko.
-- www.tudorgirba.com "Every thing has its own flow"
I also liked the debate, so before it closes I want to throw my 2 cents in: I don't think this is an issue about inheritance (vs composition), it is one about multiple inheritance or lack thereof. You may want your object to be an announcer of events, but almost always you will also want it to be something else as well. To me this suggests that Announcer should be a trait, not a class, so in a sense, indeed, you would "compose" your classes using it, but you would use trait composition instead of class composition. In VisualAge there is a huge hierarchy underneath AbtObservableObject. Sure, there are many classes that want to participate in an observable pattern, but you should not be forced to inherit from a particular class in order to do that, so that is just another related example that would have benefited from traits. Florin On 7/22/2013 7:40 AM, Tudor Girba wrote:
I love this debate, but given the energy it attracted, I now apologize to have fueled it.
By reading the thread, I believe that everyone involved in the discussion is on the same page on 99.9% of the cases, the only real difference being the case of the Announcer (and even there, the difference is more philosophical in nature).
Would it be Ok to call it a day and move on? :)
Cheers, Doru
On Mon, Jul 22, 2013 at 1:05 PM, Igor Stasenko <siguctua@gmail.com <mailto:siguctua@gmail.com>> wrote:
On 21 July 2013 20:21, Denis Kudriashov <dionisiydk@gmail.com <mailto:dionisiydk@gmail.com>> wrote: > 2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr <mailto:stephane.ducasse@inria.fr>> >> >> Interesting how many people in this list think that "Announcer subclass: >> #TxEditor" provides special implementation of announcer named TxEditor? >> >> >> Many >> this is composition using inheritance and inheritance should not be used >> like that. >> >> Announcer subclass: #GreedyAnnouncer >> >> Announcer subclass: #RemoteAnnouncer > > > And if we prefer composition we should not implement such kind of hierarchy. > We should implement GreadySubscriptionsRegistry, RemoteSubscriptionsRegistry > or AsynchSubscriptionsRegistry and reuse existed Announcer. All subscribing > and delivering logic implemented by subscription registry. Announcer is just > simple delegator with convenient api to create Subscription instances: > > Announcer>>subscribe: anAnnouncementClass do: aValuable > "Declare that when anAnnouncementClass is raised, aValuable is executed." > ^ registry add: ( > AnnouncementSubscription new > announcer: self; > announcementClass: anAnnouncementClass; > valuable: aValuable) > > > Announcer>>announce: anAnnouncement > > | announcement | > announcement := anAnnouncement asAnnouncement. > registry ifNotNil: [ > registry deliver: announcement > ]. > ^ announcement > > All magic happens inside #add: and #deliver: methods of > SubscriptionsRegistry. > > Also announcements framework provides very nice feature: you can have > announcer as last argument of event handler selector (that's why > AnnouncementSubscription contains reference to announcer instance): > > announcer on: MyEvent send: #handleAnnouncement:raisedBy: to: aSubscriber > > Without subclassing YourEventsSource from Announcer you will not have such > feature. Or you will need implement complex subscription method inside > YourEventSource which will delegates special event handler to its announcer >
1. you don't need separate class to represent event source. it can be any object which does:
announcer announce: Foo.
in any place.. I do not see any practical gains from forming a separate class for this role. It is barely formalizeable because the way how users creating and triggering events is arbitrary.
2. SubscriptionRegistry is an implementation detail. It is private. It is a way how Announcer doing things inside. It should be no concern of anything outside to consider what it does. You won't find this class in VisualWorks implementation, for instance.
3. again, event source - is any object which says 'announcer announce: ...' It is NOT announcer, because announcer is an event dispatcher. dispatcher ~= source Is it so hard to see a difference?
When you subclass from Announcer, is that you want to say:
'self announce:' , so the very same object acts both as event source and event dispatcher.
But then , as Stef said, by subclassing you inheriting API. So, what prevents me from writing following code, in my own class, which uses your domain object in a following way:
coolDomainObject := YourDomainObjectWhichInheritsFromAnnouncer new.
coolDomainObject on: Foo do: #bar. coolDomainObject announce: Foo.
That i guess is not something you expected, huh? But why not? As long as your object understand this protocol, and as long as you don't overriding original behavior of Announcer, i can abuse your object in a way you did not expected. And this is a consequence of violating principle of least authority.
Because once you declare that we're free to use subclassing for any purpose, then, i can declare: i am free to use any subclass of Announcer as announcer for myself.
Lets write random code, do not follow any rules and everyone will be happy.
--- Best regards, Igor Stasenko.
-- www.tudorgirba.com <http://www.tudorgirba.com>
"Every thing has its own flow"
On 22 July 2013 14:13, Florin Mateoc <fmateoc@gmail.com> wrote:
I also liked the debate, so before it closes I want to throw my 2 cents in:
I don't think this is an issue about inheritance (vs composition), it is one about multiple inheritance or lack thereof. You may want your object to be an announcer of events, but almost always you will also want it to be something else as well. To me this suggests that Announcer should be a trait, not a class, so in a sense, indeed, you would "compose" your classes using it, but you would use trait composition instead of class composition. In VisualAge there is a huge hierarchy underneath AbtObservableObject. Sure, there are many classes that want to participate in an observable pattern, but you should not be forced to inherit from a particular class in order to do that, so that is just another related example that would have benefited from traits.
Again, announcer of events means event source role. It is distinct from 'delivery service' role. When you write mail, you just drop it into mailbox, and then mr. Postman delivers it to receiver, but not directly yourself. That's what you get from specialization. But if you wanna play as mr. Postman, and also will deliver pizzas, and fly to the moon, this is called generalization, and straightly opposite to specialization.
Florin
On 7/22/2013 7:40 AM, Tudor Girba wrote:
I love this debate, but given the energy it attracted, I now apologize to have fueled it.
By reading the thread, I believe that everyone involved in the discussion is on the same page on 99.9% of the cases, the only real difference being the case of the Announcer (and even there, the difference is more philosophical in nature).
Would it be Ok to call it a day and move on? :)
Cheers, Doru
On Mon, Jul 22, 2013 at 1:05 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 21 July 2013 20:21, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor?
Many this is composition using inheritance and inheritance should not be used like that.
Announcer subclass: #GreedyAnnouncer
Announcer subclass: #RemoteAnnouncer
And if we prefer composition we should not implement such kind of hierarchy. We should implement GreadySubscriptionsRegistry, RemoteSubscriptionsRegistry or AsynchSubscriptionsRegistry and reuse existed Announcer. All subscribing and delivering logic implemented by subscription registry. Announcer is just simple delegator with convenient api to create Subscription instances:
Announcer>>subscribe: anAnnouncementClass do: aValuable "Declare that when anAnnouncementClass is raised, aValuable is executed." ^ registry add: ( AnnouncementSubscription new announcer: self; announcementClass: anAnnouncementClass; valuable: aValuable)
Announcer>>announce: anAnnouncement
| announcement | announcement := anAnnouncement asAnnouncement. registry ifNotNil: [ registry deliver: announcement ]. ^ announcement
All magic happens inside #add: and #deliver: methods of SubscriptionsRegistry.
Also announcements framework provides very nice feature: you can have announcer as last argument of event handler selector (that's why AnnouncementSubscription contains reference to announcer instance):
announcer on: MyEvent send: #handleAnnouncement:raisedBy: to: aSubscriber
Without subclassing YourEventsSource from Announcer you will not have such feature. Or you will need implement complex subscription method inside YourEventSource which will delegates special event handler to its announcer
1. you don't need separate class to represent event source. it can be any object which does:
announcer announce: Foo.
in any place.. I do not see any practical gains from forming a separate class for this role. It is barely formalizeable because the way how users creating and triggering events is arbitrary.
2. SubscriptionRegistry is an implementation detail. It is private. It is a way how Announcer doing things inside. It should be no concern of anything outside to consider what it does. You won't find this class in VisualWorks implementation, for instance.
3. again, event source - is any object which says 'announcer announce: ...' It is NOT announcer, because announcer is an event dispatcher. dispatcher ~= source Is it so hard to see a difference?
When you subclass from Announcer, is that you want to say:
'self announce:' , so the very same object acts both as event source and event dispatcher.
But then , as Stef said, by subclassing you inheriting API. So, what prevents me from writing following code, in my own class, which uses your domain object in a following way:
coolDomainObject := YourDomainObjectWhichInheritsFromAnnouncer new.
coolDomainObject on: Foo do: #bar. coolDomainObject announce: Foo.
That i guess is not something you expected, huh? But why not? As long as your object understand this protocol, and as long as you don't overriding original behavior of Announcer, i can abuse your object in a way you did not expected. And this is a consequence of violating principle of least authority.
Because once you declare that we're free to use subclassing for any purpose, then, i can declare: i am free to use any subclass of Announcer as announcer for myself.
Lets write random code, do not follow any rules and everyone will be happy.
--- Best regards, Igor Stasenko.
-- www.tudorgirba.com
"Every thing has its own flow"
-- Best regards, Igor Stasenko.
On 7/22/2013 8:44 AM, Igor Stasenko wrote:
On 22 July 2013 14:13, Florin Mateoc <fmateoc@gmail.com> wrote:
I also liked the debate, so before it closes I want to throw my 2 cents in:
I don't think this is an issue about inheritance (vs composition), it is one about multiple inheritance or lack thereof. You may want your object to be an announcer of events, but almost always you will also want it to be something else as well. To me this suggests that Announcer should be a trait, not a class, so in a sense, indeed, you would "compose" your classes using it, but you would use trait composition instead of class composition. In VisualAge there is a huge hierarchy underneath AbtObservableObject. Sure, there are many classes that want to participate in an observable pattern, but you should not be forced to inherit from a particular class in order to do that, so that is just another related example that would have benefited from traits.
Again, announcer of events means event source role. It is distinct from 'delivery service' role.
When you write mail, you just drop it into mailbox, and then mr. Postman delivers it to receiver, but not directly yourself. That's what you get from specialization. But if you wanna play as mr. Postman, and also will deliver pizzas, and fly to the moon, this is called generalization, and straightly opposite to specialization.
So what? The thing is, you want to do both. We think in both directions. Sometimes we generalize from the existing knowledge, sometimes we specialize from the abstract. A quaternion is a generalization in 4 dimensions, we did not get complex numbers by specializing from quaternions, it was the other way around. Florin
On 22 July 2013 15:13, Florin Mateoc <fmateoc@gmail.com> wrote:
On 7/22/2013 8:44 AM, Igor Stasenko wrote:
On 22 July 2013 14:13, Florin Mateoc <fmateoc@gmail.com> wrote:
I also liked the debate, so before it closes I want to throw my 2 cents in:
I don't think this is an issue about inheritance (vs composition), it is one about multiple inheritance or lack thereof. You may want your object to be an announcer of events, but almost always you will also want it to be something else as well. To me this suggests that Announcer should be a trait, not a class, so in a sense, indeed, you would "compose" your classes using it, but you would use trait composition instead of class composition. In VisualAge there is a huge hierarchy underneath AbtObservableObject. Sure, there are many classes that want to participate in an observable pattern, but you should not be forced to inherit from a particular class in order to do that, so that is just another related example that would have benefited from traits.
Again, announcer of events means event source role. It is distinct from 'delivery service' role.
When you write mail, you just drop it into mailbox, and then mr. Postman delivers it to receiver, but not directly yourself. That's what you get from specialization. But if you wanna play as mr. Postman, and also will deliver pizzas, and fly to the moon, this is called generalization, and straightly opposite to specialization.
So what? The thing is, you want to do both. We think in both directions. Sometimes we generalize from the existing knowledge, sometimes we specialize from the abstract.
I say you what. If you go to extreme, then your object can do everything.. and so you end up with code like this everywhere: self foo: self bar with: self zork. Because your object knows everything, can do everything and don't needs anything. The only question which remains is why you using object-oriented language then? Why using classes, caring about inheritance, polymorphism , message passing etc, because if single object does all you need, you don't need all of above. My point is that if you don't need such concepts, just don't use them.. but if you using them, then please follow the rules. Same goes to Announcer. It defines the certain way how it should be used. And how its not.
A quaternion is a generalization in 4 dimensions, we did not get complex numbers by specializing from quaternions, it was the other way around.
hmm? how that? i first time hear that they are related. Can you provide a real example where you can mix both of them interchangeably? Besides the fact that they both are partial case of n-dimentional vectors, they not sharing too much, because of different math and different uses. But anyways.. it seems like Announcement(s) model, to my thinking don't really fits well with observer pattern. Because in observer pattern you need only 2 roles: observer(s) and subject. You don't have nor need a mediator or 'event dispatcher', which represented by announcer. Implementing an observer pattern using Announcer is an overkill, to my thinking. Reflecting by your example, is like using quaternions where complex numbers is sufficient. I think more and more, in this regard, that Announcements is not a silver bullet and it has own limits and intended ways to use. For that matter, i think we should have more simple and elegant solution. Because subclassing from Announcer is not a solution. -- Best regards, Igor Stasenko.
Because the quaternion (ar + ai * i + 0 * j + 0 * k) will behave exactly like a complex (ar + ai * i) with respect to arithmetic (+ - * /) and elementary functions (exp sin cos etc...). 2013/7/22 Igor Stasenko <siguctua@gmail.com>
On 22 July 2013 15:13, Florin Mateoc <fmateoc@gmail.com> wrote:
On 7/22/2013 8:44 AM, Igor Stasenko wrote:
On 22 July 2013 14:13, Florin Mateoc <fmateoc@gmail.com> wrote:
I also liked the debate, so before it closes I want to throw my 2 cents in:
I don't think this is an issue about inheritance (vs composition), it is one about multiple inheritance or lack thereof. You may want your object to be an announcer of events, but almost always you will also want it to be something else as well. To me this suggests that Announcer should be a trait, not a class, so in a sense, indeed, you would "compose" your classes using it, but you would use trait composition instead of class composition. In VisualAge there is a huge hierarchy underneath AbtObservableObject. Sure, there are many classes that want to participate in an observable pattern, but you should not be forced to inherit from a particular class in order to do that, so that is just another related example that would have benefited from traits.
Again, announcer of events means event source role. It is distinct from 'delivery service' role.
When you write mail, you just drop it into mailbox, and then mr. Postman delivers it to receiver, but not directly yourself. That's what you get from specialization. But if you wanna play as mr. Postman, and also will deliver pizzas, and fly to the moon, this is called generalization, and straightly opposite to specialization.
So what? The thing is, you want to do both. We think in both directions. Sometimes we generalize from the existing knowledge, sometimes we specialize from the abstract.
I say you what. If you go to extreme, then your object can do everything.. and so you end up with code like this everywhere:
self foo: self bar with: self zork.
Because your object knows everything, can do everything and don't needs anything. The only question which remains is why you using object-oriented language then? Why using classes, caring about inheritance, polymorphism , message passing etc, because if single object does all you need, you don't need all of above.
My point is that if you don't need such concepts, just don't use them.. but if you using them, then please follow the rules.
Same goes to Announcer. It defines the certain way how it should be used. And how its not.
A quaternion is a generalization in 4 dimensions, we did not get complex numbers by specializing from quaternions, it was the other way around.
hmm? how that? i first time hear that they are related. Can you provide a real example where you can mix both of them interchangeably? Besides the fact that they both are partial case of n-dimentional vectors, they not sharing too much, because of different math and different uses.
But anyways.. it seems like Announcement(s) model, to my thinking don't really fits well with observer pattern. Because in observer pattern you need only 2 roles: observer(s) and subject. You don't have nor need a mediator or 'event dispatcher', which represented by announcer.
Implementing an observer pattern using Announcer is an overkill, to my thinking. Reflecting by your example, is like using quaternions where complex numbers is sufficient.
I think more and more, in this regard, that Announcements is not a silver bullet and it has own limits and intended ways to use. For that matter, i think we should have more simple and elegant solution. Because subclassing from Announcer is not a solution.
-- Best regards, Igor Stasenko.
On 22 July 2013 16:23, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Because the quaternion (ar + ai * i + 0 * j + 0 * k) will behave exactly like a complex (ar + ai * i) with respect to arithmetic (+ - * /) and elementary functions (exp sin cos etc...).
all i know is that i*i = -1 that's what makes complex numbers quite different from other n-dimensional vector(s). and i never seen that you can mix complex algebra and linear algebra.. hence, i can imagine that you can subclass both from some abstract NDimensionalVector but not subclass one from another, because it makes no sense.
2013/7/22 Igor Stasenko <siguctua@gmail.com>
On 22 July 2013 15:13, Florin Mateoc <fmateoc@gmail.com> wrote:
On 7/22/2013 8:44 AM, Igor Stasenko wrote:
On 22 July 2013 14:13, Florin Mateoc <fmateoc@gmail.com> wrote:
I also liked the debate, so before it closes I want to throw my 2 cents in:
I don't think this is an issue about inheritance (vs composition), it is one about multiple inheritance or lack thereof. You may want your object to be an announcer of events, but almost always you will also want it to be something else as well. To me this suggests that Announcer should be a trait, not a class, so in a sense, indeed, you would "compose" your classes using it, but you would use trait composition instead of class composition. In VisualAge there is a huge hierarchy underneath AbtObservableObject. Sure, there are many classes that want to participate in an observable pattern, but you should not be forced to inherit from a particular class in order to do that, so that is just another related example that would have benefited from traits.
Again, announcer of events means event source role. It is distinct from 'delivery service' role.
When you write mail, you just drop it into mailbox, and then mr. Postman delivers it to receiver, but not directly yourself. That's what you get from specialization. But if you wanna play as mr. Postman, and also will deliver pizzas, and fly to the moon, this is called generalization, and straightly opposite to specialization.
So what? The thing is, you want to do both. We think in both directions. Sometimes we generalize from the existing knowledge, sometimes we specialize from the abstract.
I say you what. If you go to extreme, then your object can do everything.. and so you end up with code like this everywhere:
self foo: self bar with: self zork.
Because your object knows everything, can do everything and don't needs anything. The only question which remains is why you using object-oriented language then? Why using classes, caring about inheritance, polymorphism , message passing etc, because if single object does all you need, you don't need all of above.
My point is that if you don't need such concepts, just don't use them.. but if you using them, then please follow the rules.
Same goes to Announcer. It defines the certain way how it should be used. And how its not.
A quaternion is a generalization in 4 dimensions, we did not get complex numbers by specializing from quaternions, it was the other way around.
hmm? how that? i first time hear that they are related. Can you provide a real example where you can mix both of them interchangeably? Besides the fact that they both are partial case of n-dimentional vectors, they not sharing too much, because of different math and different uses.
But anyways.. it seems like Announcement(s) model, to my thinking don't really fits well with observer pattern. Because in observer pattern you need only 2 roles: observer(s) and subject. You don't have nor need a mediator or 'event dispatcher', which represented by announcer.
Implementing an observer pattern using Announcer is an overkill, to my thinking. Reflecting by your example, is like using quaternions where complex numbers is sufficient.
I think more and more, in this regard, that Announcements is not a silver bullet and it has own limits and intended ways to use. For that matter, i think we should have more simple and elegant solution. Because subclassing from Announcer is not a solution.
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
Forget about quaternions! Are you really saying: specialization good, generalization bad?!!! Well, at least in this case, your generalization is indeed a bad one :) Generalization and specialization are duals of each other. We can do stupid specializations just as easily as we can do stupid generalizations. Let's take you example. Postman subclass: PostmanWhoAlsoDeliversPizzasAndFliesToTheMoon is a specialization, not a generalization. How is it any better? On Mon, Jul 22, 2013 at 10:38 AM, Igor Stasenko <siguctua@gmail.com> wrote:
On 22 July 2013 16:23, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Because the quaternion (ar + ai * i + 0 * j + 0 * k) will behave exactly like a complex (ar + ai * i) with respect to arithmetic (+ - * /) and elementary functions (exp sin cos etc...).
all i know is that
i*i = -1
that's what makes complex numbers quite different from other n-dimensional vector(s). and i never seen that you can mix complex algebra and linear algebra.. hence, i can imagine that you can subclass both from some abstract NDimensionalVector but not subclass one from another, because it makes no sense.
2013/7/22 Igor Stasenko <siguctua@gmail.com>
On 22 July 2013 15:13, Florin Mateoc <fmateoc@gmail.com> wrote:
On 7/22/2013 8:44 AM, Igor Stasenko wrote:
On 22 July 2013 14:13, Florin Mateoc <fmateoc@gmail.com> wrote:
I also liked the debate, so before it closes I want to throw my 2 cents in:
I don't think this is an issue about inheritance (vs composition),
it
is one about multiple inheritance or lack thereof. You may want your object to be an announcer of events, but almost always you will also want it to be something else as well. To me this suggests that Announcer should be a trait, not a class, so in a sense, indeed, you would "compose" your classes using it, but you would use trait composition instead of class composition. In VisualAge there is a huge hierarchy underneath AbtObservableObject. Sure, there are many classes that want to participate in an observable pattern, but you should not be forced to inherit from a particular class in order to do that, so that is just another related example that would have benefited from traits.
Again, announcer of events means event source role. It is distinct from 'delivery service' role.
When you write mail, you just drop it into mailbox, and then mr. Postman delivers it to receiver, but not directly yourself. That's what you get from specialization. But if you wanna play as mr. Postman, and also will deliver pizzas, and fly to the moon, this is called generalization, and straightly opposite to specialization.
So what? The thing is, you want to do both. We think in both directions. Sometimes we generalize from the existing knowledge, sometimes we specialize from the abstract.
I say you what. If you go to extreme, then your object can do everything.. and so you end up with code like this everywhere:
self foo: self bar with: self zork.
Because your object knows everything, can do everything and don't needs anything. The only question which remains is why you using object-oriented language then? Why using classes, caring about inheritance, polymorphism , message passing etc, because if single object does all you need, you don't need all of above.
My point is that if you don't need such concepts, just don't use them.. but if you using them, then please follow the rules.
Same goes to Announcer. It defines the certain way how it should be used. And how its not.
A quaternion is a generalization in 4 dimensions, we did not get complex numbers by specializing from quaternions, it was the other way around.
hmm? how that? i first time hear that they are related. Can you provide a real example where you can mix both of them interchangeably? Besides the fact that they both are partial case of n-dimentional vectors, they not sharing too much, because of different math and different uses.
But anyways.. it seems like Announcement(s) model, to my thinking don't really fits well with observer pattern. Because in observer pattern you need only 2 roles: observer(s) and subject. You don't have nor need a mediator or 'event dispatcher', which represented by announcer.
Implementing an observer pattern using Announcer is an overkill, to my thinking. Reflecting by your example, is like using quaternions where complex numbers is sufficient.
I think more and more, in this regard, that Announcements is not a silver bullet and it has own limits and intended ways to use. For that matter, i think we should have more simple and elegant solution. Because subclassing from Announcer is not a solution.
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
On 22 July 2013 16:52, Florin Mateoc <fmateoc@gmail.com> wrote:
Forget about quaternions! Are you really saying: specialization good, generalization bad?!!! Well, at least in this case, your generalization is indeed a bad one :)
Generalization and specialization are duals of each other. We can do stupid specializations just as easily as we can do stupid generalizations. Let's take you example. Postman subclass: PostmanWhoAlsoDeliversPizzasAndFliesToTheMoon is a specialization, not a generalization. How is it any better?
uh? Generalization is good. but you don't achieving it by subclassing. And that's exactly what i was pointing out: subclassing is intended for specialization, but not for generalization. And when you subclass for generalization you doing exactly what i am against.
On Mon, Jul 22, 2013 at 10:38 AM, Igor Stasenko <siguctua@gmail.com> wrote:
On 22 July 2013 16:23, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote:
Because the quaternion (ar + ai * i + 0 * j + 0 * k) will behave exactly like a complex (ar + ai * i) with respect to arithmetic (+ - * /) and elementary functions (exp sin cos etc...).
all i know is that
i*i = -1
that's what makes complex numbers quite different from other n-dimensional vector(s). and i never seen that you can mix complex algebra and linear algebra.. hence, i can imagine that you can subclass both from some abstract NDimensionalVector but not subclass one from another, because it makes no sense.
2013/7/22 Igor Stasenko <siguctua@gmail.com>
On 22 July 2013 15:13, Florin Mateoc <fmateoc@gmail.com> wrote:
On 7/22/2013 8:44 AM, Igor Stasenko wrote:
On 22 July 2013 14:13, Florin Mateoc <fmateoc@gmail.com> wrote:
I also liked the debate, so before it closes I want to throw my 2 cents in:
I don't think this is an issue about inheritance (vs composition), it is one about multiple inheritance or lack thereof. You may want your object to be an announcer of events, but almost always you will also want it to be something else as well. To me this suggests that Announcer should be a trait, not a class, so in a sense, indeed, you would "compose" your classes using it, but you would use trait composition instead of class composition. In VisualAge there is a huge hierarchy underneath AbtObservableObject. Sure, there are many classes that want to participate in an observable pattern, but you should not be forced to inherit from a particular class in order to do that, so that is just another related example that would have benefited from traits.
Again, announcer of events means event source role. It is distinct from 'delivery service' role.
When you write mail, you just drop it into mailbox, and then mr. Postman delivers it to receiver, but not directly yourself. That's what you get from specialization. But if you wanna play as mr. Postman, and also will deliver pizzas, and fly to the moon, this is called generalization, and straightly opposite to specialization.
So what? The thing is, you want to do both. We think in both directions. Sometimes we generalize from the existing knowledge, sometimes we specialize from the abstract.
I say you what. If you go to extreme, then your object can do everything.. and so you end up with code like this everywhere:
self foo: self bar with: self zork.
Because your object knows everything, can do everything and don't needs anything. The only question which remains is why you using object-oriented language then? Why using classes, caring about inheritance, polymorphism , message passing etc, because if single object does all you need, you don't need all of above.
My point is that if you don't need such concepts, just don't use them.. but if you using them, then please follow the rules.
Same goes to Announcer. It defines the certain way how it should be used. And how its not.
A quaternion is a generalization in 4 dimensions, we did not get complex numbers by specializing from quaternions, it was the other way around.
hmm? how that? i first time hear that they are related. Can you provide a real example where you can mix both of them interchangeably? Besides the fact that they both are partial case of n-dimentional vectors, they not sharing too much, because of different math and different uses.
But anyways.. it seems like Announcement(s) model, to my thinking don't really fits well with observer pattern. Because in observer pattern you need only 2 roles: observer(s) and subject. You don't have nor need a mediator or 'event dispatcher', which represented by announcer.
Implementing an observer pattern using Announcer is an overkill, to my thinking. Reflecting by your example, is like using quaternions where complex numbers is sufficient.
I think more and more, in this regard, that Announcements is not a silver bullet and it has own limits and intended ways to use. For that matter, i think we should have more simple and elegant solution. Because subclassing from Announcer is not a solution.
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
-- Best regards, Igor Stasenko.
On 7/22/13, Tudor Girba <tudor@tudorgirba.com> wrote:
I love this debate, but given the energy it attracted, I now apologize to have fueled it.
By reading the thread, I believe that everyone involved in the discussion is on the same page on 99.9% of the cases, +1 the only real difference being the case of the Announcer (and even there, the difference is more philosophical in nature). +1
Would it be Ok to call it a day and move on? :) +1
Cheers, Doru
On Mon, Jul 22, 2013 at 1:05 PM, Igor Stasenko <siguctua@gmail.com> wrote:
On 21 July 2013 20:21, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
Interesting how many people in this list think that "Announcer subclass: #TxEditor" provides special implementation of announcer named TxEditor?
Many this is composition using inheritance and inheritance should not be used like that.
Announcer subclass: #GreedyAnnouncer
Announcer subclass: #RemoteAnnouncer
And if we prefer composition we should not implement such kind of hierarchy. We should implement GreadySubscriptionsRegistry, RemoteSubscriptionsRegistry or AsynchSubscriptionsRegistry and reuse existed Announcer. All subscribing and delivering logic implemented by subscription registry. Announcer is just simple delegator with convenient api to create Subscription instances:
Announcer>>subscribe: anAnnouncementClass do: aValuable "Declare that when anAnnouncementClass is raised, aValuable is executed." ^ registry add: ( AnnouncementSubscription new announcer: self; announcementClass: anAnnouncementClass; valuable: aValuable)
Announcer>>announce: anAnnouncement
| announcement | announcement := anAnnouncement asAnnouncement. registry ifNotNil: [ registry deliver: announcement ]. ^ announcement
All magic happens inside #add: and #deliver: methods of SubscriptionsRegistry.
Also announcements framework provides very nice feature: you can have announcer as last argument of event handler selector (that's why AnnouncementSubscription contains reference to announcer instance):
announcer on: MyEvent send: #handleAnnouncement:raisedBy: to: aSubscriber
Without subclassing YourEventsSource from Announcer you will not have such feature. Or you will need implement complex subscription method inside YourEventSource which will delegates special event handler to its announcer
1. you don't need separate class to represent event source. it can be any object which does:
announcer announce: Foo.
in any place.. I do not see any practical gains from forming a separate class for this role. It is barely formalizeable because the way how users creating and triggering events is arbitrary.
2. SubscriptionRegistry is an implementation detail. It is private. It is a way how Announcer doing things inside. It should be no concern of anything outside to consider what it does. You won't find this class in VisualWorks implementation, for instance.
3. again, event source - is any object which says 'announcer announce: ...' It is NOT announcer, because announcer is an event dispatcher. dispatcher ~= source Is it so hard to see a difference?
When you subclass from Announcer, is that you want to say:
'self announce:' , so the very same object acts both as event source and event dispatcher.
But then , as Stef said, by subclassing you inheriting API. So, what prevents me from writing following code, in my own class, which uses your domain object in a following way:
coolDomainObject := YourDomainObjectWhichInheritsFromAnnouncer new.
coolDomainObject on: Foo do: #bar. coolDomainObject announce: Foo.
That i guess is not something you expected, huh? But why not? As long as your object understand this protocol, and as long as you don't overriding original behavior of Announcer, i can abuse your object in a way you did not expected. And this is a consequence of violating principle of least authority.
Because once you declare that we're free to use subclassing for any purpose, then, i can declare: i am free to use any subclass of Announcer as announcer for myself.
Lets write random code, do not follow any rules and everyone will be happy.
--- Best regards, Igor Stasenko.
-- www.tudorgirba.com
"Every thing has its own flow"
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
Announcer subclass: #Customer
And what I should do if I want Customer which can trigger events? Do you think "EventSource subclass: #Customer" make any difference? Or do you think we should never use inheritance to make domain announcer classes? What the existed alternative? I don't want always add announcer instance and couple equal methods any time I need it. In practice in both cases my domain classes will never override methods from "events support superclass". And to me name "Announcer" is exactly events source. Is my english so bad here? Maybe we should rename it to "AnnouncerMediator" and real Announcer class? Best regards, Denis
And what I should do if I want Customer which can trigger events?
then ask yourself about the API of your customer Do you want the full API of Announcer? I doubt.
Do you think "EventSource subclass: #Customer" make any difference? Or do you think we should never use inheritance to make domain announcer classes? What the existed alternative? I don't want always add announcer instance and couple equal methods any time I need it.
Think about API not about code reuse. Think about polymorphic objects. Each time you subclass from Announcer ALL the API should make sense. We should use subclassing when you can potentially replace instance of the superclass by instance of the subclasses at least from the API point of you and that existing code calling the superclass still somehow work.
In practice in both cases my domain classes will never override methods from "events support superclass".
And to me name "Announcer" is exactly events source. Is my english so bad here? Maybe we should rename it to "AnnouncerMediator" and real Announcer class?
I like the distinction made by igor. I do not want to think in terms of Registry. I do not care in fact. I care that I have a class that can register and announce.
Best regards, Denis
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
And what I should do if I want Customer which can trigger events?
then ask yourself about the API of your customer Do you want the full API of Announcer? I doubt.
Do you think "EventSource subclass: #Customer" make any difference? Or do you think we should never use inheritance to make domain announcer classes? What the existed alternative? I don't want always add announcer instance and couple equal methods any time I need it.
Think about API not about code reuse. Think about polymorphic objects. Each time you subclass from Announcer ALL the API should make sense.
What is all api of Announcer? It is just two methods: #announce: and #on:send:to:. When I need "object with events" I always need this methods. What problem?
On Jul 21, 2013, at 9:27 PM, Denis Kudriashov <dionisiydk@gmail.com> wrote:
2013/7/21 Stéphane Ducasse <stephane.ducasse@inria.fr>
And what I should do if I want Customer which can trigger events?
then ask yourself about the API of your customer Do you want the full API of Announcer? I doubt.
Do you think "EventSource subclass: #Customer" make any difference? Or do you think we should never use inheritance to make domain announcer classes? What the existed alternative? I don't want always add announcer instance and couple equal methods any time I need it.
Think about API not about code reuse. Think about polymorphic objects. Each time you subclass from Announcer ALL the API should make sense.
What is all api of Announcer?
Announcer allSelectors
It is just two methods: #announce: and #on:send:to:.
No!! this is exactly my point. When you inherit from a class you get its API merged into the one of your class.
When I need "object with events" I always need this methods. What problem?
We should not use subclassing for code reuse but use subclassing for subtyping (= polymorphic interface). This is not because we have a dynamically typed language that we should not use subtyping. Have a look at my lecture there are slides on subtyping. Compare: OrderedCollection subclass: #Poem of course a poem is a collection of word. Now it is not a subtype of collection!!! OrderedCollection subclass: #UniqueOrderedCollection or compare OrderedCollection subclass: #Stack vs. Stack subclass: #HanoiStack Think in terms of API and polymorphic objects Stef
2013/7/22 Stéphane Ducasse <stephane.ducasse@inria.fr>
This is not because we have a dynamically typed language that we should not use subtyping. Have a look at my lecture there are slides on subtyping.
Compare:
OrderedCollection subclass: #Poem of course a poem is a collection of word. Now it is not a subtype of collection!!! OrderedCollection subclass: #UniqueOrderedCollection
or compare
OrderedCollection subclass: #Stack
vs.
Stack subclass: #HanoiStack
Think in terms of API and polymorphic objects
I agree with your examples. And I never build my domain "container like classes" as subclass of OrderedCollection (or friends). But Announcer to me is different concern. It is like subclassing Object as Tudor said. What is all api of Announcer?
Announcer allSelectors
It should be "Announcer selectors" (it is 16 methods). And I think it is wrong to name all methods of class as API. And I think Announcer API can be reduced to just 5 methods: #announce:, #on:do, #subscribe:send:to:, #unsubscribe:and #week. All others are private or just convenient aliases (maybe already deprecated). And this 5 methods is exactly what I need to subscribe on "event service" with enough flexibility. So when I implement my domain "event source" I need superclass which will supply to my service such nice API. And now there is only Announcer class for this. I were look at Announcer hierarchy. What do you think about SystemAnnouncer class? It has strange implementation. It is subclass of Announcer and it has another announcer instance named "private".
participants (10)
-
Camillo Bruni -
Denis Kudriashov -
Florin Mateoc -
H. Hirzel -
Igor Stasenko -
Max Leske -
Nicolas Cellier -
Sebastian Tleye -
Stéphane Ducasse -
Tudor Girba