Why this walkback when opening a view ?

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

Why this walkback when opening a view ?

Ken Lee-2
Friends -

I have a package that I installed into a clean image. The app that is
contained in the package runs perfectly, and its main view opens fine.

The app allows the user to browse a collection of people, and view
information about them. The person class contains a bunch of other classes,
each of which contain some other classes.

The problem: I simply added an instance variable to one of those nested
classes, and now the main app won't open.

Method STBCollectionProxy(STBProxy)stbFixup: at: iterates through its
dictionary, and eventually encounters Dictionary>>add: anAssociation.

That method sends the "key" method to the association, which happens to be
an instance of SmallInteger - which causes the walkback.

My guess is that somehow, the shell view knows about the objects that it
displays - but I never set things up that way.

I seem to remember some facility for exporting views separately from
"business logic". Could someone help me unglue these things, so that I can
change the business objects again ?

Thanks so much !

- Ken


Reply | Threaded
Open this post in threaded view
|

Re: Why this walkback when opening a view ?

Bill Schwab
Ken,

> The app allows the user to browse a collection of people, and view
> information about them. The person class contains a bunch of other
classes,
> each of which contain some other classes.
>
> The problem: I simply added an instance variable to one of those nested
> classes, and now the main app won't open.

It sounds like you have an instance captured (probably as a model) by one of
your view resource, and when it's in-filed from the resource, the instance
variables don't line up.  Have a look at STB Layout Changes on

  http://www.object-arts.com/wiki/html/Dolphin/BinaryFiler.htm

That should allow you to do a #nextPut:, either of nil or a reasonable
default value, to make your views work again.

Assuming that the layout change caused the problem, the conversion method
will "fix" the view immediately, and you really don't need to do anything
else.  However, it doesn't hurt to re-save the view resource to capture an
updated STB stream for your model - that way, the conversion won't need to
run every time you (or your end users) open the view.  You can "script" the
VC to open and save multiple view resources if that's appropriate.

FWIW, I've gotten away from deliberately capturing models in view resources.
I'm not saying it's a bad practice, but, it didn't help enough to justify
the break on refactoring that came with it.  I considered creating a "dummy"
class with just enough behavior to look like one of the models, but with no
instance variables.  The idea would be to have the views capture that object
and then have it replaced by a presenter in #onViewOpened.  As it turns out,
that doesn't work terribly well because the point of capturing things in
views (IMHO) is to make them look right in the VC, and that can't happen
with a dummy object.  So, I end up with "holes" in the VC, but no STB
hassles.  Caveat emptor: I've changed my mind on this before, and might do
so again :)

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Why this walkback when opening a view ?

Ken Lee-2
Bill -

> It sounds like you have an instance captured (probably as a model) by one of
> your view resource, and when it's in-filed from the resource, the instance
> variables don't line up.  Have a look at STB Layout Changes on
>
>   http://www.object-arts.com/wiki/html/Dolphin/BinaryFiler.htm
>
> That should allow you to do a #nextPut:, either of nil or a reasonable
> default value, to make your views work again.

Thanks for your response - but could you please elaborate on this a
little ?

Frankly, I am surprised that Dolphin somehow allows a View to know so
much about an object it presents, that it becomes impossible to change
the object - but that's just me !

- Ken


Reply | Threaded
Open this post in threaded view
|

Re: Why this walkback when opening a view ?

Bill Schwab-2
Ken,

> Thanks for your response - but could you please elaborate on this a
> little ?

First, make a backup in case this gets ugly.

Assuming that you never changed the version number, it will be zero, so add
a class-side #stbVersion to answer 1.  File in #stbConvertFrom: - it almost
always works as-is, unless you are messing around with views themselves; you
are changing a model so it will probably be fine.  Then create a
#stbConvertFromVersion0: method, also on the class-side; #stbConvertFrom:
will call it as needed.

You might try setting a breakpoint in the last method and opening one of the
offending views in the VC, which should give you a chance to look at the
data that you are given for the conversion.  Basically, you get an array of
the instance variables of the old-format object that you are about to
convert, and you need to create an array of instance variables for it in the
new format.  Streams are a nice way to do the job.

The example from the Wiki:

Something class>>stbConvertFromVersion0:versionArray
   "Private - Convert version 0 notes to version 1 format.  Added #helpText
and #searchTag
   as the fourth and fifth instance variables; note that subclasses will
have ivs starting
   at four, and these need to slide down by two.  To acheive this, copy
across the first
   three instance variables, put a couple of nils, and then copy the
remainder of the
   data.  Something and its subclasses all have the same STB version, at
least for now.

   See ResourceAccessor for the source of this stream trick; there, the
change
   is a little simpler as the added variable appears at the beginning of the
list."

      | versionStream |

   versionStream := versionArray readStream.

   ^Array writeStream
      nextPutAll:( versionStream next:3 );
      nextPut:nil; "helpText"
      nextPut:nil; "searchTag"
      nextPutAll:versionStream upToEnd;
      contents

This basically just shoves across three instance variables that the two
formats have in common, and adds nil place-holders for two more that have
been added - in your case, you might specify default values other than nil.
The #upToEnd is something that often (though not always!) takes care of
subclasses.

In short, think of variables in slots, and your job is to make sure that the
new format slots have the right things in them.  The more you changed, the
more you have to work at it.

Note that as you add future changes and corresponding STB version numbers,
you'll add #stbConvertFromVersion*: methods, each of which does one
incremental conversion.  For example, your future #stbConvertFromVersion1:
method will get a version one input and create a version 2 output.
#stbConvertFrom: will call as many of the methods as needed to make the
overall conversion.


> Frankly, I am surprised that Dolphin somehow allows a View to know so
> much about an object it presents, that it becomes impossible to change
> the object - but that's just me !

It _can_ be quite useful.  Consider a custom view that draws some kind of
design diagram, and suppose that the diagrams always have some kind of
border or something.  Ok, I'm stretching a bit, but, by placing a model in
the view, the border, perhaps drawn by the model, can appear in the VC as
the view is being edited, and aspects of that model can be changed to
provide different starting points in different view resource names.

OTOH, it is STB dependent, and can be quite a break on change.  Having tried
both approaches, I'm pretty steadily doing setup from
Presenter>>onViewOpened, with the cost that my views don't necessarily "look
right" in the VC, but, they don't cause me the kinds of problems you are
having right now.  Also, as tempting as "just edit it in the VC" might be,
the problem is that after a while, the configuration details are easy to
forget.

Any specific questions?  This is daunting at first and gets a lot easier
after you go through it a couple of times.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Why this walkback when opening a view ?

Blair McGlashan
In reply to this post by Ken Lee-2
"Ken Lee" <[hidden email]> wrote in message
news:[hidden email]...
> Bill -
>
> > It sounds like you have an instance captured (probably as a model) by
one of
> > your view resource, and when it's in-filed from the resource, the
instance

> > variables don't line up.  Have a look at STB Layout Changes on
> >
> >   http://www.object-arts.com/wiki/html/Dolphin/BinaryFiler.htm
> >
> > That should allow you to do a #nextPut:, either of nil or a reasonable
> > default value, to make your views work again.
>
> Thanks for your response - but could you please elaborate on this a
> little ?
>
> Frankly, I am surprised that Dolphin somehow allows a View to know so
> much about an object it presents, that it becomes impossible to change
> the object - but that's just me !
>
> - Ken

It may not be directly applicable in this case, but a useful trick to know
about during development is to have any view resources containing a view one
is about to add instance variables to (or otherwise modify) open in View
Composers. These "running" instances will be updated by the normal
mechanisms that the ClassBuilder uses to update existing instances when the
shape of a class changes. One can then save down the views with the new
shape. Obviously one must open the view resources before modifying the class
definition, or if one forgets to do that it is probably worth reversing out
the change temporarily so that one can load up the view resources.

Other useful tips to minimize the amount of work one needs to do writing STB
conversions:
- Add some spare instance variables. This is certainly worth doing when one
finds the need to write an STB conversion, as otherwise it will probably
become necessary again in the near future.
- Avoid rearranging the instance variables (and that includes deleting old
ones), since this will make the STB conversion much harder, especially if
there are subclasses.
- The STBDebugger can be helpful in finding out precisely what is ending up
in a view resource. It's use is straightforward (e.g. (STBDebugger on:
<stream>) [next|basicNext]). It isn't really a debugger so much as a
disassembler which prints its output to the Transcript.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: Why this walkback when opening a view ?

Ken Lee-2
Blair-

> It may not be directly applicable in this case, but a useful trick to know
> about during development is to have any view resources containing a view one
> is about to add instance variables to (or otherwise modify) open in View
> Composers. These "running" instances will be updated by the normal
> mechanisms that the ClassBuilder uses to update existing instances when the
> shape of a class changes. One can then save down the views with the new
> shape. Obviously one must open the view resources before modifying the class
> definition, or if one forgets to do that it is probably worth reversing out
> the change temporarily so that one can load up the view resources.

Thanks for your help !

I have tried this, but I get the same result. Perhaps I am missing
something obvious.

I have a View that contains a custom View. I opened up the main View
in the View Composer, and then added a variable to the class in
question. I saved the main View. I then tried to save the package, and
got a dialog box with the following message:

"SmallInteger does not understand #key
The package will not load if saved in this form so the package file
has not been saved.
Would you like to browse the package prerequisites in order to track
down the problem ?"

If I press the Yes button, a walkback occurs, with the message
"SmallInteger does not understand #key". If I press the Debug button
to have a look at the walkback, I get another walkback, saying the
same thing.
 
Note that the class to which I am adding an instance variable is not a
View, or the custom View, but a class that is deeply nested in the
class that is presented by the main View and its custom View. The main
view has a list presenter that shows you a list of person names, and
when you select a person, the custom View represents information about
the person. The class to which I am adding an instance variable, is
nested way down in the person class. For example, it represents
something like the phone number, to which I am adding an area code.


Reply | Threaded
Open this post in threaded view
|

Re: Why this walkback when opening a view ?

Ken Lee-2
In reply to this post by Blair McGlashan
> It may not be directly applicable in this case, but a useful trick to know
> about during development is to have any view resources containing a view one
> is about to add instance variables to (or otherwise modify) open in View
> Composers. These "running" instances will be updated by the normal
> mechanisms that the ClassBuilder uses to update existing instances when the
> shape of a class changes. One can then save down the views with the new
> shape. Obviously one must open the view resources before modifying the class
> definition, or if one forgets to do that it is probably worth reversing out
> the change temporarily so that one can load up the view resources.

In light of this not working, I have tried refactoring. I created a
new class, gave it all the same methods and instance variables, and
added a few variables. I renamed all references to the old class, to
the new one. I opened the View, and everything worked nicely. I
deleted the original class, and removed it from its package.
Nevertheless, the package cannot be saved, because there are
*invisible* references to the now-non-existent class - over which I
have no control.

I freely admit that I am unable to fix this problem by following your
or Bill's kind advice. I am not the most clever developer. At the same
time, I find this general design principle to be inconsistent with the
excellence that permeates the rest of Dolphin. Is there not some
other, simple solution - for a simpleton like me ?

Best wishes,

Ken


Reply | Threaded
Open this post in threaded view
|

Re: Why this walkback when opening a view ?

Louis Sumberg-2
Ken,

> Nevertheless, the package cannot be saved, because there are
> *invisible* references to the now-non-existent class - over which I
> have no control.

If you haven't tried already, click on the "panic" button in the Dolphin
system folder.  That often fixes things like this.  Make sure you save any
open workspaces beforehand.

-- Louis


Reply | Threaded
Open this post in threaded view
|

Re: Why this walkback when opening a view ?

Bill Schwab-2
In reply to this post by Ken Lee-2
Ken,

> In light of this not working, I have tried refactoring. I created a
> new class, gave it all the same methods and instance variables, and
> added a few variables. I renamed all references to the old class, to
> the new one. I opened the View, and everything worked nicely. I
> deleted the original class, and removed it from its package.
> Nevertheless, the package cannot be saved, because there are
> *invisible* references to the now-non-existent class - over which I
> have no control.

Latent might be a better word for them, and you do have control.  You can
either delete the view resources and rebuild them, or you can put back the
class that they need to load.  The latter might not work in your current
image because of the changes you've made.


> I freely admit that I am unable to fix this problem by following your
> or Bill's kind advice. I am not the most clever developer. At the same
> time, I find this general design principle to be inconsistent with the
> excellence that permeates the rest of Dolphin. Is there not some
> other, simple solution - for a simpleton like me ?

STB versioning is definitely not simple the first time, so don't beat
yourself up over it.  If you're willing to work through it, I'm confident
that we can fix the problem - your first step would probably be to restore
that backup I mentioned at the beginning :)  From there, a few questions and
file-ins later, we should have it working.  If you don't want to do that,
just open the resource browser and delete the broken resources, then rebuild
them.

As for this representing a "lack of excellence" in Dolphin, I don't agree.
It *is* a consequence of a design decision to use binary filed prototypes
vs. source code to create composite views.  Your options include: (1)
delete/recreate view resources that break; (2) Use STB versioning to fix
same; (3) avoid capturing your own objects in view resources; (4) use my
ViewGenerator goodie so that view resources become discardable
intermediates.  I use all of the above methods for various projects.  Simple
view resouces are often easier to recreate than to salvage.

ViewGenerator is probably too drastic for most situations.  It got started
with a seriously big presenter that is connected to a very structured model.
It was cheaper to write and debug ViewGenerator than to try to create that
monster by hand.  I use a subclass of ViewGenerator for that project.  More
recently, I've been experimenting with using it for more routine tasks, but,
it's too soon to say whether it's worth the effort.

Also, have a look at

  http://www.mitchellscientific.com/smalltalk/PresenterGenTool.htm

which tackles the MVP code generating problem from a different angle.  My
tools start with meta data and generate the whole thing, Chris' allow you to
draw the interface and then he takes over.  That won't help in your current
situation, but, you might find that it saves time for the situations that
need a little recovery work.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]