Class/object evolution and serialization

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

Class/object evolution and serialization

Sergei Gnezdov-2
Hi,

I simply serialize objects to a file.  Initially instances of MyClass
used Time objects, but now they use DateAndTime objects.  How do I do
I read files which contain old version of objects?

        Thank you
--
Sergei Gnezdov


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

Ian Bartholomew-18
Sergei,

> I simply serialize objects to a file.  Initially instances of MyClass
> used Time objects, but now they use DateAndTime objects.  How do I do
> I read files which contain old version of objects?

Reading the files shouldn't be a problem, Dolphin will just recreate
objects using the information contained in the file.  If the file
contains an instance of Time then that is what will be recreated.

I imagine the problem you are trying to get around is what happens
next - your restored class contains an instance of Time but you are now
sending it messages appropriate to a DateAndTime object.  To get round
this you will have to automatically convert the Time object into a
DateAndTime....

1) You can use the STBVersioning mechanism in MyClass.  There are plenty
of example stbConvertFromVersionX class methods in the image [1], and it
has been mentioned in the newsgroups a few times.  Basically you can
intercept the recreation of the object in the file and tweak it by
performing any conversions you need

2) The easy way is just to do a test/conversion when you read the file,
although this depends on whether the file load is done by code that you
own.  Something like....

    myClass := Object binaryReadFrom: aFileStream.
    myClass convertTimeToDateAndTime.
    ....

MyClass>>convertTimeToDateAndTime
    (time isKindOf: DateAndTime) ifTrue: [^self].
    time := DateAndTime fromTime: time

Ask again if you are having some other sort of problem with the file in.

[1] Although most of them are concerned with changes to the shape (the
number of instance variables) in the class.

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

cstb
In reply to this post by Sergei Gnezdov-2
Sergei Gnezdov wrote:

>
> Hi,
>
> I simply serialize objects to a file.  Initially instances of MyClass
> used Time objects, but now they use DateAndTime objects.  How do I do
> I read files which contain old version of objects?
>
>         Thank you
> --
> Sergei Gnezdov



*before* you make the first change of the kind you mentioned,
start including both className and version# as a header for the
stored output.  From then on, at each release, move the restore
method to restoreFromVersionX, where x is the version being replaced,
then make the changes, and modify the current save/restore methods.
And increment the stored version#, of course.

-cstb


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

Chris Uppal-3
cstb wrote:

> > I simply serialize objects to a file.  Initially instances of MyClass
> > used Time objects, but now they use DateAndTime objects.  How do I do
> > I read files which contain old version of objects?
[...]
> *before* you make the first change of the kind you mentioned,
> start including both className and version# as a header for the
> stored output.

These things are already part of the STB framework.  You do have to
increment the version number (which defaults to 1, I think) and write your own
conversion routines, of course, but STB stores the classname and version for
you.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

Bill Schwab-2
In reply to this post by cstb
> *before* you make the first change of the kind you mentioned,
> start including both className and version# as a header for the
> stored output.  From then on, at each release, move the restore
> method to restoreFromVersionX, where x is the version being replaced,
> then make the changes, and modify the current save/restore methods.
> And increment the stored version#, of course.

I have found OA's recommendation of incremental conversions to be very
sound, and STB already notes the class and version of each object.

Have a good one,

Bill

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


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

Sergei Gnezdov-2
In reply to this post by Sergei Gnezdov-2
On Wed, 21 Jan 2004 06:11:51 GMT, Sergei Gnezdov <sergei@munged> wrote:

>Hi,
>
>I simply serialize objects to a file.  Initially instances of MyClass
>used Time objects, but now they use DateAndTime objects.  How do I do
>I read files which contain old version of objects?
>
> Thank you

Thanks for the responses.

I decided to try STB based solution for a case when a new instance
variable is added to a class.  I keep getting an exception: "End of
stream" and I have no idea what to do next.  I tried to use
  self halt
and it does not work in stb methods.  Is it an indication that methods
don't execute?

I followed Education Center "Converting STB data after instance layout
changes" chapter.

MyClass is a subclass of Model class.  I know that Model has its own
#stbConvertFrom, but I don't know if it makes any difference.

Here is what I've got:

MyClass>>stbVersion
  ^1

"Copied from Education Center example."
MyClass>>stbConvertFrom: anSTBClassFormat
  | selector array newInstance |
  ^
  [:data |
  array := data.
  anSTBClassFormat version to: self stbVersion - 1
    do:
    [:version |
    selector := ('stbConvertFromVersion' , version asString , ':')
asSymbol.
    array := self perform: selector with: array].
    newInstance := self basicNew.
    1 to: self instSize do: [:i | newInstance instVarAt: i put: (array
at: i)].
    newInstance]

"this method is a complete guess based on the code in the image"
stbConvertFromVersion0: array
    | newSize |
    newSize := array size + 1. "1 instance variable was added"
    ^(Array new: newSize)
        replaceFrom: 1
        to: array size
        with: array
        startingAt: 1;
        at: newSize put: 0;
        yourself


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

Bill Schwab-2
Sergei,

> I decided to try STB based solution for a case when a new instance
> variable is added to a class.  I keep getting an exception: "End of
> stream" and I have no idea what to do next.  I tried to use
>   self halt
> and it does not work in stb methods.  Is it an indication that methods
> don't execute?

Yes.  I have often set breakpoints in STB conversion methods, and had no
problems.  The only other thing I've seen (quite often recently, FWIW) is a
debugger that fails to open because of print string problems.  Invariably,
there is something else wrong that leads to the problem, but the debugger
sometimes falls victim to it :(


> I followed Education Center "Converting STB data after instance layout
> changes" chapter.
>
> MyClass is a subclass of Model class.  I know that Model has its own
> #stbConvertFrom, but I don't know if it makes any difference.

You must be careful to work with it rather than against it.  For that
reason, I much prefer to subclass Object (which is not allowed to have
instance variables, hence avoiding the problems of what to do when both OA
and I want to change them).


> Here is what I've got:
>
> MyClass>>stbVersion
>   ^1

That makes objects that you save now be at version 1, but so would have been
any previously saved objects, thanks to the method on Model.  In short, you
have not changed the version number, which is a risk any time you subclass
base system classes that have instance variables.



> "this method is a complete guess based on the code in the image"
> stbConvertFromVersion0: array
>     | newSize |
>     newSize := array size + 1. "1 instance variable was added"
>     ^(Array new: newSize)
>         replaceFrom: 1
>         to: array size
>         with: array
>         startingAt: 1;
>         at: newSize put: 0;
>         yourself

I much prefer to use streams, one to read the old format content and one to
write the new version array.  There are samples in the image.

Have a good one,

Bill

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


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

Ian Bartholomew-18
In reply to this post by Sergei Gnezdov-2
Sergei,

> MyClass is a subclass of Model class.  I know that Model has its own
> #stbConvertFrom, but I don't know if it makes any difference.

OA added the extra Model instVar some time ago so it's _very_ unlikely
you will come across a Model that was saved under stbVersion 0.  Taking
that into account you can just assume that the underlying Model will use
stbVersion 1 and make things a lot easier.  NB This does mean that if OA
change the shape of the Model class in future then your code will also
need changing!

Add the following ....

MyModel class>>stbVersion
    ^99

This just ensures that the stbVersion number will not match for your
original saved instances.  You could just use 2, the next logical
version number, but you may cause yourself a bit of confusion if OA
update Model to stbVersion 2.


MyModel class>>stbConvertFrom: anSTBClassFormat
    ^[:data |
    | newInst |
    newInst := self basicNew.
    data keysAndValuesDo: [:i :v | newInst instVarAt: i put: v].
    newInst updateTimeToDateAndTime.
    newInst]

You will also need to add a MyModel>>updateTimeToDateAndTime method that
checks to see if the appropriate instVar contains a Time and, if so,
updates it to a DateAndTime.

All the above method does is copy across the instVars, the class shape
is the same so a direct copy is ok, and then allows the new instance to
be updated.

NB (again) This will _only_ work if your class and it's superclasses
have the save number of instVars as they did when the instance was
saved.  If not then you will need to get a bit more creative.

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

Bill Schwab-2
Ian, Sergei,

It would probably be best to override #stbSaveOn: to use a custom STB proxy.
The proxy can start out at version one, and increment without fear of
conflict with OA's changes.

Have a good one,

Bill

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


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

Sergei Gnezdov-2
In reply to this post by Sergei Gnezdov-2
On Tue, 27 Jan 2004 07:49:45 GMT, Sergei Gnezdov <sergei@munged> wrote:

>On Wed, 21 Jan 2004 06:11:51 GMT, Sergei Gnezdov <sergei@munged> wrote:
>
>>Hi,
>>
>>I simply serialize objects to a file.  
[snip]
>>  How do I do
>>I read files which contain old version of objects?

>I decided to try STB based solution for a case when a new instance
>variable is added to a class.  I keep getting an exception: "End of
>stream" and I have no idea what to do next.  I tried to use
>  self halt
>and it does not work in stb methods.

Thanks.  The answers helped as usual :)

The stb code is executed when I update version number to be higher
then one, so breakpoints work.

The following code solves a problem when new instance variable was
added to a MyClass.  The class itself is a subclass of the Model
class.

MyClass>>stbVersion
  "Use version 101, because superclass (Model) uses version 1."
  ^101

MyClass>>stbConvertFrom: anSTBClassFormat
  "Convert from earlier binary filed versions."

  | newInstance array |
  ^
  [:data |
  array := self stbConvertFromVersion1: data.
  newInstance := self basicNew.
  1 to: self instSize do: [:i | newInstance instVarAt: i put: (array
at: i)].
  newInstance]

MyClass>>stbConvertFromVersion1: array
  "Private - Perform an STB conversion from a version 1
  (comes from Model) to version 101 (comes from MyClass).

  | newSize |

  newSize := array size + 1.  "1 instance variable was added"
  ^(Array new: newSize)
    replaceFrom: 1
      to: array size
      with: array
      startingAt: 1;
    at: newSize put: nil;  "new var is initialized to nil"
    yourself


Reply | Threaded
Open this post in threaded view
|

Re: Class/object evolution and serialization

Sergei Gnezdov-2
In reply to this post by Bill Schwab-2
On Tue, 27 Jan 2004 12:50:16 -0500, "Bill Schwab"
<[hidden email]> wrote:

>Ian, Sergei,
>
>It would probably be best to override #stbSaveOn: to use a custom STB proxy.
>The proxy can start out at version one, and increment without fear of
>conflict with OA's changes.
>
>Have a good one,
>
>Bill

I am somewhat confused about the following statements (my own
creation, oh...):

It is recommended to use Model to create user specific Model classes.
It is not recommended to use Model if data is serialized, because
model classes are not that easy to version.

Which class should I base my model on?  Should I just use STB proxy
next time?