Hi,
My first time posting here. Hopefully I've found the right list for my question.
I've created a JavaScript MVC framework for browser applications. The popular JavaScript "MVC frameworks" are not really MVC so I decided to build one that actually is. (https://github.com/petermichaux/maria) Although I'm not a Smalltalk programmer, I've used the Squeak View and Controller classes as my primary implementation inspiration. There are many places in my JavaScript code that are line-by-line ports from Squeak. I've found that the few times I've experimented and deviated from the principles of the Squeak View class, I've usually ended up in hot water and reverted.
I've been considering one deviation for a long time in my versions of the Controller|release and View|model:controller: methods because I just cannot grasp the motivation for why the Squeak code works as it does. The Squeak code for Controller|release is
release "Breaks the cycle between the receiver and its view. It is usually not necessary to send release provided the receiver's view has been properly released independently."
model := nil. view ~~ nil ifTrue: [view controller: nil. view := nil]
and the View|model:controller: method
model: aModel controller: aController "Set the receiver's model to aModel, add the receiver to aModel's list of dependents, and set the receiver's controller to aController. Subsequent changes to aModel (see Model|change) will result in View|update: messages being sent to the receiver. #NoControllerAllowed for the value of aController indicates that no default controller is available; nil for the value of aController indicates that the default controller is to be used when needed. If aController is neither #NoControllerAllowed nor nil, its view is set to the receiver and its model is set to aModel."
model ~~ nil & (model ~~ aModel) ifTrue: [model removeDependent: self]. aModel ~~ nil & (aModel ~~ model) ifTrue: [aModel addDependent: self]. model := aModel. aController ~~ nil ifTrue: [aController view: self. aController model: aModel]. controller := aController
By the nature of the strategy pattern, controller objects are intended to be swapped in and out of view objects to modify the behavior of a view. The problem that I see is that when changing the controller of a view, the View|model:controller: method does not nil the view of the previous controller which is being replaced. This means that several controller objects can exist pointing to the same view (but the view will only point to one controller.) If the release message is sent to a controller that is not the view's current controller, then the view still looses it current controller!
I'm not very good at writing Smalltalk but to illustrate the point, I'll give it a try...
alphaController := Controller new. betaController := Controller new. view := View new. view setController alphaController. view setController betaController. alphaController release.
That last line will actually remove betaController from view which seems like bad behaviour to me.
One solution is to modify View|model:controller: to nil the previous controller's view. Another solution would be to modify Controller|release so that the controller checks that it is the view's current controller before the line "view controller: nil." Both of these could be done together.
I'm very curious to know why the Squeak Controller|release and View|model:controller: methods seem to leave this seemingly trouble spot open. Thanks for any thoughts you can share on this issue.
Peter
On Sun, Jul 8, 2012 at 9:19 AM, Peter Michaux petermichaux@gmail.com wrote:
My first time posting here. Hopefully I've found the right list for my question.
Hi Peter,
I'm not an authority on MVC, and I can't tell you why anything is the way it is, but I will say that this is definitely the right place for the question.
Maria looks really interesting. Thanks for sharing.
Colin
Hi Peter -
Your observations are correct. First, IIRC the reason for Controller>>release is to aid the garbage collector. In some early versions of Smalltalk, the GCs weren't capable of detecting cycles so having the view point to the controller, and the controller point to the view would not allow any of them to be GCed, thus the need to call Controller>>release.
As to View>>model:controller: and its interaction with Controller>>release, I think your observation and cure are both entirely correct. Since you are doing a reimplementation I would probably just stay away from Controller>>release alltogether. There should not be a need to ever call this, all modern systems have GCs that can cope with this problem. But if you want to keep release, checking for being the current controller should work just fine.
It might also be worthwhile to check out VisualWorks NC (another heir to ST80 with a more modern incarnation of an MVC framework) to see if Controller>>release is still present there and if so, what it actually does :-)
Cheers, - Andreas
Peter Michaux wrote
Hi,
My first time posting here. Hopefully I've found the right list for my question.
I've created a JavaScript MVC framework for browser applications. The popular JavaScript "MVC frameworks" are not really MVC so I decided to build one that actually is. (https://github.com/petermichaux/maria) Although I'm not a Smalltalk programmer, I've used the Squeak View and Controller classes as my primary implementation inspiration. There are many places in my JavaScript code that are line-by-line ports from Squeak. I've found that the few times I've experimented and deviated from the principles of the Squeak View class, I've usually ended up in hot water and reverted.
I've been considering one deviation for a long time in my versions of the Controller|release and View|model:controller: methods because I just cannot grasp the motivation for why the Squeak code works as it does. The Squeak code for Controller|release is
release "Breaks the cycle between the receiver and its view. It is usually not necessary to send release provided the receiver's view has been properly released independently." model := nil. view ~~ nil ifTrue: [view controller: nil. view := nil]
and the View|model:controller: method
model: aModel controller: aController "Set the receiver's model to aModel, add the receiver to aModel's list of dependents, and set the receiver's controller to aController. Subsequent changes to aModel (see Model|change) will result in View|update: messages being sent to the receiver. #NoControllerAllowed for the value of aController indicates that no default controller is available; nil for the value of aController indicates that the default controller is to be used when needed. If aController is neither #NoControllerAllowed nor nil, its view is set to the receiver and its model is set to aModel." model ~~ nil & (model ~~ aModel) ifTrue: [model removeDependent: self]. aModel ~~ nil & (aModel ~~ model) ifTrue: [aModel addDependent: self]. model := aModel. aController ~~ nil ifTrue: [aController view: self. aController model: aModel]. controller := aController
By the nature of the strategy pattern, controller objects are intended to be swapped in and out of view objects to modify the behavior of a view. The problem that I see is that when changing the controller of a view, the View|model:controller: method does not nil the view of the previous controller which is being replaced. This means that several controller objects can exist pointing to the same view (but the view will only point to one controller.) If the release message is sent to a controller that is not the view's current controller, then the view still looses it current controller!
I'm not very good at writing Smalltalk but to illustrate the point, I'll give it a try...
alphaController := Controller new. betaController := Controller new. view := View new. view setController alphaController. view setController betaController. alphaController release.
That last line will actually remove betaController from view which seems like bad behaviour to me.
One solution is to modify View|model:controller: to nil the previous controller's view. Another solution would be to modify Controller|release so that the controller checks that it is the view's current controller before the line "view controller: nil." Both of these could be done together.
I'm very curious to know why the Squeak Controller|release and View|model:controller: methods seem to leave this seemingly trouble spot open. Thanks for any thoughts you can share on this issue.
Peter
-- View this message in context: http://forum.world.st/Controller-release-and-View-model-controller-methods-t... Sent from the Squeak - Dev mailing list archive at Nabble.com.
There is also a really excellent MVC image prepared by Sungjin Chun that was recently discussed on the list. You can find it here: http://nxt-web.googlecode.com/files/ST80-MVC.zip
I would suggest that you grab a copy of this and look at it for reference. Try running that image, then open a few browsers and a workspace. In the workspace you can try doing "inspect it" on each of these three code snippets in order to start getting an idea of where the dependents are:
"find all controllers and inspect their dependents" Smalltalk garbageCollect. Controller allSubInstances collect: [:e | e dependents].
"find all models and inspect their dependents" Smalltalk garbageCollect. Model allSubInstances collect: [:e | e dependents].
"find all views and inspect their dependents" Smalltalk garbageCollect. View allSubInstances collect: [:e | e dependents].
I'm not sure that there is actually any dependency between views and controllers at all, so the Controller>>release method may be misleading in that regard (Andreas explained why the method is there). On the other hand, views will register themselves as dependents of a model, and one model can have many dependent views. You can see this happening in the View>>model:controller: method that you quoted, where the view (i.e. self in this method) checks to see if it already has a model (model ~~ nil & (model ~~ aModel)) and if so removes itself as a dependent of that model (model removeDependent: self). It then adds itself as a dependent of a new model (aModel addDependent: self). But as far as I know, controllers do not normally have any dependents at all, so the Controller>>release method very likely does nothing at all most of the time.
Dave
On Sun, Jul 08, 2012 at 12:31:08PM -0700, Andreas.Raab wrote:
Hi Peter -
Your observations are correct. First, IIRC the reason for Controller>>release is to aid the garbage collector. In some early versions of Smalltalk, the GCs weren't capable of detecting cycles so having the view point to the controller, and the controller point to the view would not allow any of them to be GCed, thus the need to call Controller>>release.
As to View>>model:controller: and its interaction with Controller>>release, I think your observation and cure are both entirely correct. Since you are doing a reimplementation I would probably just stay away from Controller>>release alltogether. There should not be a need to ever call this, all modern systems have GCs that can cope with this problem. But if you want to keep release, checking for being the current controller should work just fine.
It might also be worthwhile to check out VisualWorks NC (another heir to ST80 with a more modern incarnation of an MVC framework) to see if Controller>>release is still present there and if so, what it actually does :-)
Cheers,
- Andreas
Peter Michaux wrote
Hi,
My first time posting here. Hopefully I've found the right list for my question.
I've created a JavaScript MVC framework for browser applications. The popular JavaScript "MVC frameworks" are not really MVC so I decided to build one that actually is. (https://github.com/petermichaux/maria) Although I'm not a Smalltalk programmer, I've used the Squeak View and Controller classes as my primary implementation inspiration. There are many places in my JavaScript code that are line-by-line ports from Squeak. I've found that the few times I've experimented and deviated from the principles of the Squeak View class, I've usually ended up in hot water and reverted.
I've been considering one deviation for a long time in my versions of the Controller|release and View|model:controller: methods because I just cannot grasp the motivation for why the Squeak code works as it does. The Squeak code for Controller|release is
release "Breaks the cycle between the receiver and its view. It is usually not necessary to send release provided the receiver's view has been properly released independently." model := nil. view ~~ nil ifTrue: [view controller: nil. view := nil]
and the View|model:controller: method
model: aModel controller: aController "Set the receiver's model to aModel, add the receiver to aModel's list of dependents, and set the receiver's controller to aController. Subsequent changes to aModel (see Model|change) will result in View|update: messages being sent to the receiver. #NoControllerAllowed for the value of aController indicates that no default controller is available; nil for the value of aController indicates that the default controller is to be used when needed. If aController is neither #NoControllerAllowed nor nil, its view is set to the receiver and its model is set to aModel." model ~~ nil & (model ~~ aModel) ifTrue: [model removeDependent: self]. aModel ~~ nil & (aModel ~~ model) ifTrue: [aModel addDependent: self]. model := aModel. aController ~~ nil ifTrue: [aController view: self. aController model: aModel]. controller := aController
By the nature of the strategy pattern, controller objects are intended to be swapped in and out of view objects to modify the behavior of a view. The problem that I see is that when changing the controller of a view, the View|model:controller: method does not nil the view of the previous controller which is being replaced. This means that several controller objects can exist pointing to the same view (but the view will only point to one controller.) If the release message is sent to a controller that is not the view's current controller, then the view still looses it current controller!
I'm not very good at writing Smalltalk but to illustrate the point, I'll give it a try...
alphaController := Controller new. betaController := Controller new. view := View new. view setController alphaController. view setController betaController. alphaController release.
That last line will actually remove betaController from view which seems like bad behaviour to me.
One solution is to modify View|model:controller: to nil the previous controller's view. Another solution would be to modify Controller|release so that the controller checks that it is the view's current controller before the line "view controller: nil." Both of these could be done together.
I'm very curious to know why the Squeak Controller|release and View|model:controller: methods seem to leave this seemingly trouble spot open. Thanks for any thoughts you can share on this issue.
Peter
-- View this message in context: http://forum.world.st/Controller-release-and-View-model-controller-methods-t... Sent from the Squeak - Dev mailing list archive at Nabble.com.
Hi Dave,
Thanks for your response.
In Squeak, it appears views are not dependents of controllers or vice versa. Models are the only players in the MVC triad that have dependents. The view and controller know about each other but they aren't dependents in the Smalltalk sense.
I'm wondering if Controller>>release is worth keeping around as an empty method just so sub-classes can implement that method if necessary.
Peter
On Sun, Jul 8, 2012 at 1:06 PM, David T. Lewis lewis@mail.msen.com wrote:
There is also a really excellent MVC image prepared by Sungjin Chun that was recently discussed on the list. You can find it here: http://nxt-web.googlecode.com/files/ST80-MVC.zip
I would suggest that you grab a copy of this and look at it for reference. Try running that image, then open a few browsers and a workspace. In the workspace you can try doing "inspect it" on each of these three code snippets in order to start getting an idea of where the dependents are:
"find all controllers and inspect their dependents" Smalltalk garbageCollect. Controller allSubInstances collect: [:e | e dependents].
"find all models and inspect their dependents" Smalltalk garbageCollect. Model allSubInstances collect: [:e | e dependents].
"find all views and inspect their dependents" Smalltalk garbageCollect. View allSubInstances collect: [:e | e dependents].
I'm not sure that there is actually any dependency between views and controllers at all, so the Controller>>release method may be misleading in that regard (Andreas explained why the method is there). On the other hand, views will register themselves as dependents of a model, and one model can have many dependent views. You can see this happening in the View>>model:controller: method that you quoted, where the view (i.e. self in this method) checks to see if it already has a model (model ~~ nil & (model ~~ aModel)) and if so removes itself as a dependent of that model (model removeDependent: self). It then adds itself as a dependent of a new model (aModel addDependent: self). But as far as I know, controllers do not normally have any dependents at all, so the Controller>>release method very likely does nothing at all most of the time.
Dave
On Sun, Jul 08, 2012 at 12:31:08PM -0700, Andreas.Raab wrote:
Hi Peter -
Your observations are correct. First, IIRC the reason for Controller>>release is to aid the garbage collector. In some early versions of Smalltalk, the GCs weren't capable of detecting cycles so having the view point to the controller, and the controller point to the view would not allow any of them to be GCed, thus the need to call Controller>>release.
As to View>>model:controller: and its interaction with Controller>>release, I think your observation and cure are both entirely correct. Since you are doing a reimplementation I would probably just stay away from Controller>>release alltogether. There should not be a need to ever call this, all modern systems have GCs that can cope with this problem. But if you want to keep release, checking for being the current controller should work just fine.
It might also be worthwhile to check out VisualWorks NC (another heir to ST80 with a more modern incarnation of an MVC framework) to see if Controller>>release is still present there and if so, what it actually does :-)
Cheers,
- Andreas
Peter Michaux wrote
Hi,
My first time posting here. Hopefully I've found the right list for my question.
I've created a JavaScript MVC framework for browser applications. The popular JavaScript "MVC frameworks" are not really MVC so I decided to build one that actually is. (https://github.com/petermichaux/maria) Although I'm not a Smalltalk programmer, I've used the Squeak View and Controller classes as my primary implementation inspiration. There are many places in my JavaScript code that are line-by-line ports from Squeak. I've found that the few times I've experimented and deviated from the principles of the Squeak View class, I've usually ended up in hot water and reverted.
I've been considering one deviation for a long time in my versions of the Controller|release and View|model:controller: methods because I just cannot grasp the motivation for why the Squeak code works as it does. The Squeak code for Controller|release is
release "Breaks the cycle between the receiver and its view. It is usually not necessary to send release provided the receiver's view has been properly released independently." model := nil. view ~~ nil ifTrue: [view controller: nil. view := nil]
and the View|model:controller: method
model: aModel controller: aController "Set the receiver's model to aModel, add the receiver to aModel's list of dependents, and set the receiver's controller to aController. Subsequent changes to aModel (see Model|change) will result in View|update: messages being sent to the receiver. #NoControllerAllowed for the value of aController indicates that no default controller is available; nil for the value of aController indicates that the default controller is to be used when needed. If aController is neither #NoControllerAllowed nor nil, its view is set to the receiver and its model is set to aModel." model ~~ nil & (model ~~ aModel) ifTrue: [model removeDependent: self]. aModel ~~ nil & (aModel ~~ model) ifTrue: [aModel addDependent: self]. model := aModel. aController ~~ nil ifTrue: [aController view: self. aController model: aModel]. controller := aController
By the nature of the strategy pattern, controller objects are intended to be swapped in and out of view objects to modify the behavior of a view. The problem that I see is that when changing the controller of a view, the View|model:controller: method does not nil the view of the previous controller which is being replaced. This means that several controller objects can exist pointing to the same view (but the view will only point to one controller.) If the release message is sent to a controller that is not the view's current controller, then the view still looses it current controller!
I'm not very good at writing Smalltalk but to illustrate the point, I'll give it a try...
alphaController := Controller new. betaController := Controller new. view := View new. view setController alphaController. view setController betaController. alphaController release.
That last line will actually remove betaController from view which seems like bad behaviour to me.
One solution is to modify View|model:controller: to nil the previous controller's view. Another solution would be to modify Controller|release so that the controller checks that it is the view's current controller before the line "view controller: nil." Both of these could be done together.
I'm very curious to know why the Squeak Controller|release and View|model:controller: methods seem to leave this seemingly trouble spot open. Thanks for any thoughts you can share on this issue.
Peter
-- View this message in context: http://forum.world.st/Controller-release-and-View-model-controller-methods-t... Sent from the Squeak - Dev mailing list archive at Nabble.com.
It's quite likely that Controller>>release is no longer necessary. That said, I would not want to make any discretionary changes to MVC in Squeak trunk until the basic MVC framework is restored to good health, such that all the browsers and debuggers work properly again in MVC.
But there should be no need to put Controller>>release into your framework. Based on Andreas' explanation I think that you can safely consider it to be historical baggage.
Dave
On Sun, Jul 08, 2012 at 01:39:28PM -0700, Peter Michaux wrote:
Hi Dave,
Thanks for your response.
In Squeak, it appears views are not dependents of controllers or vice versa. Models are the only players in the MVC triad that have dependents. The view and controller know about each other but they aren't dependents in the Smalltalk sense.
I'm wondering if Controller>>release is worth keeping around as an empty method just so sub-classes can implement that method if necessary.
Peter
On Sun, Jul 8, 2012 at 1:06 PM, David T. Lewis lewis@mail.msen.com wrote:
There is also a really excellent MVC image prepared by Sungjin Chun that was recently discussed on the list. You can find it here: http://nxt-web.googlecode.com/files/ST80-MVC.zip
I would suggest that you grab a copy of this and look at it for reference. Try running that image, then open a few browsers and a workspace. In the workspace you can try doing "inspect it" on each of these three code snippets in order to start getting an idea of where the dependents are:
"find all controllers and inspect their dependents" Smalltalk garbageCollect. Controller allSubInstances collect: [:e | e dependents].
"find all models and inspect their dependents" Smalltalk garbageCollect. Model allSubInstances collect: [:e | e dependents].
"find all views and inspect their dependents" Smalltalk garbageCollect. View allSubInstances collect: [:e | e dependents].
I'm not sure that there is actually any dependency between views and controllers at all, so the Controller>>release method may be misleading in that regard (Andreas explained why the method is there). On the other hand, views will register themselves as dependents of a model, and one model can have many dependent views. You can see this happening in the View>>model:controller: method that you quoted, where the view (i.e. self in this method) checks to see if it already has a model (model ~~ nil & (model ~~ aModel)) and if so removes itself as a dependent of that model (model removeDependent: self). It then adds itself as a dependent of a new model (aModel addDependent: self). But as far as I know, controllers do not normally have any dependents at all, so the Controller>>release method very likely does nothing at all most of the time.
Dave
On Sun, Jul 08, 2012 at 12:31:08PM -0700, Andreas.Raab wrote:
Hi Peter -
Your observations are correct. First, IIRC the reason for Controller>>release is to aid the garbage collector. In some early versions of Smalltalk, the GCs weren't capable of detecting cycles so having the view point to the controller, and the controller point to the view would not allow any of them to be GCed, thus the need to call Controller>>release.
As to View>>model:controller: and its interaction with Controller>>release, I think your observation and cure are both entirely correct. Since you are doing a reimplementation I would probably just stay away from Controller>>release alltogether. There should not be a need to ever call this, all modern systems have GCs that can cope with this problem. But if you want to keep release, checking for being the current controller should work just fine.
It might also be worthwhile to check out VisualWorks NC (another heir to ST80 with a more modern incarnation of an MVC framework) to see if Controller>>release is still present there and if so, what it actually does :-)
Cheers,
- Andreas
Peter Michaux wrote
Hi,
My first time posting here. Hopefully I've found the right list for my question.
I've created a JavaScript MVC framework for browser applications. The popular JavaScript "MVC frameworks" are not really MVC so I decided to build one that actually is. (https://github.com/petermichaux/maria) Although I'm not a Smalltalk programmer, I've used the Squeak View and Controller classes as my primary implementation inspiration. There are many places in my JavaScript code that are line-by-line ports from Squeak. I've found that the few times I've experimented and deviated from the principles of the Squeak View class, I've usually ended up in hot water and reverted.
I've been considering one deviation for a long time in my versions of the Controller|release and View|model:controller: methods because I just cannot grasp the motivation for why the Squeak code works as it does. The Squeak code for Controller|release is
release "Breaks the cycle between the receiver and its view. It is usually not necessary to send release provided the receiver's view has been properly released independently." model := nil. view ~~ nil ifTrue: [view controller: nil. view := nil]
and the View|model:controller: method
model: aModel controller: aController "Set the receiver's model to aModel, add the receiver to aModel's list of dependents, and set the receiver's controller to aController. Subsequent changes to aModel (see Model|change) will result in View|update: messages being sent to the receiver. #NoControllerAllowed for the value of aController indicates that no default controller is available; nil for the value of aController indicates that the default controller is to be used when needed. If aController is neither #NoControllerAllowed nor nil, its view is set to the receiver and its model is set to aModel." model ~~ nil & (model ~~ aModel) ifTrue: [model removeDependent: self]. aModel ~~ nil & (aModel ~~ model) ifTrue: [aModel addDependent: self]. model := aModel. aController ~~ nil ifTrue: [aController view: self. aController model: aModel]. controller := aController
By the nature of the strategy pattern, controller objects are intended to be swapped in and out of view objects to modify the behavior of a view. The problem that I see is that when changing the controller of a view, the View|model:controller: method does not nil the view of the previous controller which is being replaced. This means that several controller objects can exist pointing to the same view (but the view will only point to one controller.) If the release message is sent to a controller that is not the view's current controller, then the view still looses it current controller!
I'm not very good at writing Smalltalk but to illustrate the point, I'll give it a try...
alphaController := Controller new. betaController := Controller new. view := View new. view setController alphaController. view setController betaController. alphaController release.
That last line will actually remove betaController from view which seems like bad behaviour to me.
One solution is to modify View|model:controller: to nil the previous controller's view. Another solution would be to modify Controller|release so that the controller checks that it is the view's current controller before the line "view controller: nil." Both of these could be done together.
I'm very curious to know why the Squeak Controller|release and View|model:controller: methods seem to leave this seemingly trouble spot open. Thanks for any thoughts you can share on this issue.
Peter
-- View this message in context: http://forum.world.st/Controller-release-and-View-model-controller-methods-t... Sent from the Squeak - Dev mailing list archive at Nabble.com.
Hi Andreas,
Thanks for your response.
I had a feeling that Controller>>release was there to break loops to aid reference counting garbage collectors. I've considered removing the release method from my implementation as modern JavaScript garbage collectors do not use reference counting (though Internet Explorer 6 did have reference counting and reference loop leaks for certain kinds of host objects.)
I had a look at VisualWorks NC's View and Controller classes. Thanks for the recommendation. Neither class has a release method. That is understandable for the Controller class for the reason you mentioned. I was surprised that setting the model of a view in their implementation does not automatically add the view as a dependent of the model. That is where Squeak's View>>release method is still needed.
Peter
On Sun, Jul 8, 2012 at 12:31 PM, Andreas.Raab andreas.raab@gmx.de wrote:
Hi Peter -
Your observations are correct. First, IIRC the reason for Controller>>release is to aid the garbage collector. In some early versions of Smalltalk, the GCs weren't capable of detecting cycles so having the view point to the controller, and the controller point to the view would not allow any of them to be GCed, thus the need to call Controller>>release.
As to View>>model:controller: and its interaction with Controller>>release, I think your observation and cure are both entirely correct. Since you are doing a reimplementation I would probably just stay away from Controller>>release alltogether. There should not be a need to ever call this, all modern systems have GCs that can cope with this problem. But if you want to keep release, checking for being the current controller should work just fine.
It might also be worthwhile to check out VisualWorks NC (another heir to ST80 with a more modern incarnation of an MVC framework) to see if Controller>>release is still present there and if so, what it actually does :-)
Cheers,
- Andreas
Peter Michaux wrote
Hi,
My first time posting here. Hopefully I've found the right list for my question.
I've created a JavaScript MVC framework for browser applications. The popular JavaScript "MVC frameworks" are not really MVC so I decided to build one that actually is. (https://github.com/petermichaux/maria) Although I'm not a Smalltalk programmer, I've used the Squeak View and Controller classes as my primary implementation inspiration. There are many places in my JavaScript code that are line-by-line ports from Squeak. I've found that the few times I've experimented and deviated from the principles of the Squeak View class, I've usually ended up in hot water and reverted.
I've been considering one deviation for a long time in my versions of the Controller|release and View|model:controller: methods because I just cannot grasp the motivation for why the Squeak code works as it does. The Squeak code for Controller|release is
release "Breaks the cycle between the receiver and its view. It is usually not necessary to send release provided the receiver's view has been properly released independently." model := nil. view ~~ nil ifTrue: [view controller: nil. view := nil]
and the View|model:controller: method
model: aModel controller: aController "Set the receiver's model to aModel, add the receiver to aModel's list of dependents, and set the receiver's controller to aController. Subsequent changes to aModel (see Model|change) will result in View|update: messages being sent to the receiver. #NoControllerAllowed for the value of aController indicates that no default controller is available; nil for the value of aController indicates that the default controller is to be used when needed. If aController is neither #NoControllerAllowed nor nil, its view is set to the receiver and its model is set to aModel." model ~~ nil & (model ~~ aModel) ifTrue: [model removeDependent: self]. aModel ~~ nil & (aModel ~~ model) ifTrue: [aModel addDependent: self]. model := aModel. aController ~~ nil ifTrue: [aController view: self. aController model: aModel]. controller := aController
By the nature of the strategy pattern, controller objects are intended to be swapped in and out of view objects to modify the behavior of a view. The problem that I see is that when changing the controller of a view, the View|model:controller: method does not nil the view of the previous controller which is being replaced. This means that several controller objects can exist pointing to the same view (but the view will only point to one controller.) If the release message is sent to a controller that is not the view's current controller, then the view still looses it current controller!
I'm not very good at writing Smalltalk but to illustrate the point, I'll give it a try...
alphaController := Controller new. betaController := Controller new. view := View new. view setController alphaController. view setController betaController. alphaController release.
That last line will actually remove betaController from view which seems like bad behaviour to me.
One solution is to modify View|model:controller: to nil the previous controller's view. Another solution would be to modify Controller|release so that the controller checks that it is the view's current controller before the line "view controller: nil." Both of these could be done together.
I'm very curious to know why the Squeak Controller|release and View|model:controller: methods seem to leave this seemingly trouble spot open. Thanks for any thoughts you can share on this issue.
Peter
-- View this message in context: http://forum.world.st/Controller-release-and-View-model-controller-methods-t... Sent from the Squeak - Dev mailing list archive at Nabble.com.
squeak-dev@lists.squeakfoundation.org