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 |
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 |
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] |
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 |
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 |
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 |
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 |
Free forum by Nabble | Edit this page |