Funny thing ... "True(Object)>>mustBeBoolean"

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

Funny thing ... "True(Object)>>mustBeBoolean"

Howard Oh
This is my first time that I ever wrote methods for customizing STB
filing.
I save objects with my version of #stbSaveOn:,  and restores with my
version of #stbFixup:at: .  I'm not sure that I've picked correct
methods to override.
While the process, I've encountered a walkback that made me laugh.

stbFixup: anSTBInFiler at: newObjectIndex

        | whatever debug1 |
        whatever := super stbFixup: anSTBInFiler at: newObjectIndex.
        debug1 := anSTBInFiler next.         " true is acquired."
        self assert: [debug1 class == True].  "it is a True alright."
        debug1 ifTrue: [ self halt. whatever start ]. "But it walks back
saying..."
        ^whatever



As you can see,  debug1 is an additional information read from the
filer to restore properties that are not saved in a conventional way.
(In my case, it is saving running state of a Process object).

The walk back I've got is,  "True(Object)>>mustBeBoolean".

This walkback can be avoided by removing the #ifTrue: block.

Can anybody explain what's happening there?

Best Regards


Reply | Threaded
Open this post in threaded view
|

Re: Funny thing ... "True(Object)>>mustBeBoolean"

Chris Uppal-3
Howard,

> The walk back I've got is,  "True(Object)>>mustBeBoolean".
>
> This walkback can be avoided by removing the #ifTrue: block.
>
> Can anybody explain what's happening there?

That is a nice problem ;-)

I suspect that you are mishandling STB somewhere so that the value true is not
read in the normal way (possibly because it hasn't been written in the normal
way).  If the STB system sees the STB-ed representation of true as an arbitrary
object (rather than the special case which it uses specifically for Booleans)
then it will create a new instance of class True.  And although the resulting
object is a True, it isn't == to true itself.  And only the objects true and
false themselves work with #ifTrue: etc.

You can reproduce the effect directly in a workspace (tested in D5 only):

    notReallyTrue := True basicNew.

the resulting object /thinks/ it is true.  Its #printString answers 'true'.
What's more it really is /a/ True:

    notReallyTrue class. --> True

Or even:

    notReallyTrue perform: #ifTrue:ifFalse: with: ['yes'] with: ['no'].
           --> 'yes'

So it has the right methods and they do the right thing, but if you send
#ifTrue: normally (so that the send is inlined by the compiler as a special
bytecode) then the VM doesn't recognise it:

    notReallyTrue ifTrue: ['yes']  ifFalse: ['no'].

just gives a "Must be Boolean" walkback.

If you trace through:
    true binaryStoreBytes
then you'll see how true is "pre-registered" in the writeMap.  Similarly when
reading a Boolean from STB.  I suspect that your problem is somewhere in that
area.


> This is my first time that I ever wrote methods for customizing STB
> filing.
> I save objects with my version of #stbSaveOn:,  and restores with my
> version of #stbFixup:at: .  I'm not sure that I've picked correct
> methods to override.

This may not apply to you, but if you are really changing the format in which
an object is stored (rather than just manipulating /what/ is stored, while
sticking to the standard format), then I /think/ that the best thing to do is
to override the class-side #stbReadFrom:format: method.

For instance, I have a class UnicodeCharacter and I wanted it to represent
itself compactly in STB (i.e. not as the usual STB encoding, but just as a
plain 32-bit integer).  So I overrode the instance side:

==========================
stbSaveOn: anSTBOutFiler
 "save out a binary representation of the receiver to anSTBOutFiler..  This is
 a hack to ensure that instances are represented reasonably compactly"

 anSTBOutFiler
  writePreambleFor: self;
  writeInteger: codePoint.
==========================

The preamble bit is to ensure that the class of the object is written out
before its integer value.  The codePoint is just the integer value of the
character.  On the class side:

==========================
stbReadFrom: anSTBInFiler format: anSTBClassConversion
 "read an instance of the receiver from the given binary filer.  This is
 a hack to ensure that instances are represented reasonably compactly"

 | answer |

 answer := self codePoint: (anSTBInFiler readInteger).

 anSTBInFiler register: answer.

 ^ answer.
==========================

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Funny thing ... "True(Object)>>mustBeBoolean"

Schwab,Wilhelm K
Howard, Chris,

>>This is my first time that I ever wrote methods for customizing STB
>>filing.
>>I save objects with my version of #stbSaveOn:,  and restores with my
>>version of #stbFixup:at: .  I'm not sure that I've picked correct
>>methods to override.

I use those methods for customizing storage, but note that (AFAIK) there
are very few "legal" choices, particularly in #stbSaveOn:.  Generally
you should end with a super send (or send #saveObject: yourself), and
limit yourself to overrides to nil or to a proxy.

STB proxies are not that hard to create; it just looks scary the first
time.  For STB versioning, it appears to be sufficient to simply version
the proxy and then ensure that the corresponding objects work as intended.

Note that it helps to have old STB data (which should be stored as
bytes, not instantiated objects) in globals as part of a testing of
development package associated with the "real" package.  Of course you
can also simply put a literal byte array in a test method, but I prefer
globals.  FWIW, I typically use my ZLib package (there are more complete
wrappers) to compress the captured STB data held in globals.

Have a good one,

Bill

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


Reply | Threaded
Open this post in threaded view
|

Re: Funny thing ... "True(Object)>>mustBeBoolean"

Howard Oh
In reply to this post by Chris Uppal-3
Chris,

If I follow through, "true binaryStoreBytes"

I can see is goes down into  "STBOutFiler>>basicNextPut: anObject"
which has following segment,

(refIndex := self refForObject: anObject) notNil
     ifTrue: [^self writeInteger: (STBPrefix forObjectRef: refIndex)
dword].

It finds a reference index and writes it. :-)


Well, my "stbFixup: anSTBInFiler at: newObjectIndex" reaches "True
basicNew" as your "notReallyTrue example" does.

I've twisted my buggy code a little bit like,

stbFixup: anSTBInFiler at: newObjectIndex

        | whatever |
        whatever := super stbFixup: anSTBInFiler at: newObjectIndex.
        (anSTBInFiler next class == True)
                ifTrue: [ whatever start ].
        ^whatever

which makes my TestCase pass.

I guess I'll have to let it be that way until I find a correct way to
do it.

Best Regards


Reply | Threaded
Open this post in threaded view
|

Re: Funny thing ... "True(Object)>>mustBeBoolean"

Howard Oh
In reply to this post by Schwab,Wilhelm K
Bill,

STBProxies are scarey indeed.
To be honest, I had little idea what was happening inside STB system.
It was just a wonderful serialization magic.

It really worked that way before facing its limits.
Currently, I rewire Events right after objects restored by
#binaryReadFrom:.
Restart Processes by restored hints by #stbFixup:at: .

Naive approach isn't it.  But they are my smallest code that can
possiblly work for now.  :-)

STBProxy here I come~

Best Regards


Reply | Threaded
Open this post in threaded view
|

Re: Funny thing ... "True(Object)>>mustBeBoolean"

Chris Uppal-3
In reply to this post by Howard Oh
Howard,

> Well, my "stbFixup: anSTBInFiler at: newObjectIndex" reaches "True
> basicNew" as your "notReallyTrue example" does.

It's occurred to me that there is another thing that might be going wrong here.
It could be that you have a fairly straightforward bug in either the read or
write side of your STB code.  But it could also be nothing to do with that at
all.  If, for some unrelated reason, you have extra Boolean instances in your
image, then your STB code might be working perfectly, it's just that it is
being given bad data to work with.

You can check that your image doesn't have extra Booleans by inspecting
    Boolean allSubinstances.
You should have one each of true and false ;-)  Anything else is a bit of a
problem...


It might also be worth adding temporary overrides of:
===============
    Boolean>>stbSaveOn: anSTBOutFiler
         self halt.
         ^ super stbSaveOn: anSTBOutFiler.
===============
and:
===============
    Boolean class>>stbReadFrom: anSTBInFiler format: anSTBClassConversion
         self halt.
         ^ super stbReadFrom: anSTBInFiler format: anSTBClassConversion.
===============
These shouldn't be invoked when you STB an object containing a Boolean, as you
can verify by evaluating:
    Object fromBinaryStoreBytes: (true binaryStoreBytes).
So if your code /does/ end up calling either of them then it should be easier
to track down the reason.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Funny thing ... "True(Object)>>mustBeBoolean"

Howard Oh
Chris,

The two tests of yours confirmed senity of my Dolphin image. :-)

           Boolean allSubinstances. "#(true false)"
           Object fromBinaryStoreBytes: true binaryStoreBytes.  "no
halts"


As I've been digging STB system classes to know more about them in
detail.

I've found my lousy mistake in my version of #stbSaveOn:
I didn't know that #stbSaveOn:  doesn't care if the object is nil,
SmallInteger, Character, or reference object(true is this category).
It just saves STBPrefix, Class map, Object map  barbarously.

I should have called #nextPut: which is taking care of all those
special objects and stores them properly.

===============
MyObject>>stbSaveOn: anSTBOutFiler

        super stbSaveOn: anSTBOutFiler.
        anSTBOutFiler nextPut: self isRunning  "PREVIOUSLY EVALUATED self
isRunning stbSaveOn: anSTBOutFiler WHICH WAS A MISTAKE"
===============




Now I could remove the weired #ifTrue: expressions above post to avoid
the mustBeBoolean walkback.

===============
stbFixup: anSTBInFiler at: newObjectIndex


        | whatever |
        whatever := super stbFixup: anSTBInFiler at: newObjectIndex.
        anSTBInFiler next         "(anSTBInFiler next class == True)"
                ifTrue: [ whatever start ].
        ^whatever
===============



Once again, peace is in the air. (To be honest, move on from STB
problem to other ones :-)  )

Thank you Chris&Bill

Best Regards