Controller|release and View|model:controller: methods

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Controller|release and View|model:controller: methods

Peter Michaux
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

Reply | Threaded
Open this post in threaded view
|

Re: Controller|release and View|model:controller: methods

Colin Putney-3
On Sun, Jul 8, 2012 at 9:19 AM, Peter Michaux <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

Re: Controller|release and View|model:controller: methods

Andreas.Raab
In reply to this post by Peter Michaux
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
Reply | Threaded
Open this post in threaded view
|

Re: Controller|release and View|model:controller: methods

David T. Lewis
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-tp4639127p4639147.html
> Sent from the Squeak - Dev mailing list archive at Nabble.com.

Reply | Threaded
Open this post in threaded view
|

Re: Controller|release and View|model:controller: methods

Peter Michaux
In reply to this post by Andreas.Raab
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 <[hidden email]> 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-tp4639127p4639147.html
> Sent from the Squeak - Dev mailing list archive at Nabble.com.
>

Reply | Threaded
Open this post in threaded view
|

Re: Controller|release and View|model:controller: methods

Peter Michaux
In reply to this post by David T. Lewis
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 <[hidden email]> 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-tp4639127p4639147.html
>> Sent from the Squeak - Dev mailing list archive at Nabble.com.
>

Reply | Threaded
Open this post in threaded view
|

Re: Controller|release and View|model:controller: methods

David T. Lewis
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 <[hidden email]> 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-tp4639127p4639147.html
> >> Sent from the Squeak - Dev mailing list archive at Nabble.com.
> >