[squeak-dev] Controller|release and View|model:controller: methods

Peter Michaux petermichaux at gmail.com
Sun Jul 8 16:19:39 UTC 2012


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


More information about the Squeak-dev mailing list