Pretty print any object... got a good snippet?

36 views
Skip to first unread message

Matthew Boulter

unread,
May 5, 2021, 5:59:50 AM5/5/21
to va-sma...@googlegroups.com
Hi all,
I'm reverse engineering a complex aspect of our Smalltalk application (no docs :( ).
In this sort of exercise I am a big fan of being able to pretty print the 'state' of an object at various points in the code.

I don't want to inspect live, I need it logged.

Save me sitting down and writing such a thing.

Got any good code snippets or suggest a class that's up my alley.

Appreciated. 

Regards, Matt.

Louis LaBrunda

unread,
May 5, 2021, 7:48:33 AM5/5/21
to VAST Community Forum
Hi Matt,

I'm not sure if this is what you are looking for or if you already know about it but here goes.  Many if not most classes have the #printOn: method where they print much of their internals on a stream.  If you send an instance #printString, a stream is created, #printOn: is sent with the stream and the contents of the stream are returned as a string.  If your classes don't have #printOn:, you should write it for those you are interested in.  You don't need to write #printString as #Object already has it and it will use your #printOn: method.  This is also used (in part) when you inspect instances.

Lou

Mariano Martinez Peck

unread,
May 5, 2021, 7:57:17 AM5/5/21
to VA Smalltalk
Hello Matt, 

You may want to take a look to #storeString. It prints all the instVars in a way that you can "do it" and get back an object equal to the original. 
For example, "Locale current lcTime storeString" prints:

'((LCTime basicNew)
instVarAt: 1 put: ((Array basicNew: 7)
at: 1 put: ''Sun'';
at: 2 put: ''Mon'';
at: 3 put: ''Tue'';
at: 4 put: ''Wed'';
at: 5 put: ''Thu'';
at: 6 put: ''Fri'';
at: 7 put: ''Sat'';
yourself);
instVarAt: 2 put: ((Array basicNew: 7)
at: 1 put: ''Sunday'';
at: 2 put: ''Monday'';
at: 3 put: ''Tuesday'';
at: 4 put: ''Wednesday'';
at: 5 put: ''Thursday'';
at: 6 put: ''Friday'';
at: 7 put: ''Saturday'';
yourself);
instVarAt: 3 put: ((Array basicNew: 12)
at: 1 put: ''Jan'';
at: 2 put: ''Feb'';
at: 3 put: ''Mar'';
at: 4 put: ''Apr'';
at: 5 put: ''May'';
at: 6 put: ''Jun'';
at: 7 put: ''Jul'';
at: 8 put: ''Aug'';
at: 9 put: ''Sep'';
at: 10 put: ''Oct'';
at: 11 put: ''Nov'';
at: 12 put: ''Dec'';
yourself);
instVarAt: 4 put: ((Array basicNew: 12)
at: 1 put: ''January'';
at: 2 put: ''February'';
at: 3 put: ''March'';
at: 4 put: ''April'';
at: 5 put: ''May'';
at: 6 put: ''June'';
at: 7 put: ''July'';
at: 8 put: ''August'';
at: 9 put: ''September'';
at: 10 put: ''October'';
at: 11 put: ''November'';
at: 12 put: ''December'';
yourself);
instVarAt: 5 put: ''%l:%M:%S %p %z/%f/%Y'';
instVarAt: 6 put: ''%z/%f/%Y'';
instVarAt: 7 put: ''%l:%M:%S %p'';
instVarAt: 8 put: ((Array basicNew: 2)
at: 1 put: ''AM'';
at: 2 put: ''PM'';
yourself);
instVarAt: 9 put: ''%l:%M:%S %p'';
instVarAt: 10 put: ((Array basicNew: 7)
at: 1 put: #''format_l:date:time:'';
at: 2 put: '':'';
at: 3 put: #''format_M:date:time:'';
at: 4 put: '':'';
at: 5 put: #''format_S:date:time:'';
at: 6 put: '' '';
at: 7 put: #''format_p:date:time:'';
yourself);
instVarAt: 11 put: ((Array basicNew: 5)
at: 1 put: #''format_z:date:time:'';
at: 2 put: ''/'';
at: 3 put: #''format_f:date:time:'';
at: 4 put: ''/'';
at: 5 put: #''format_Y:date:time:'';
yourself);
instVarAt: 12 put: ((Array basicNew: 13)
at: 1 put: #''format_l:date:time:'';
at: 2 put: '':'';
at: 3 put: #''format_M:date:time:'';
at: 4 put: '':'';
at: 5 put: #''format_S:date:time:'';
at: 6 put: '' '';
at: 7 put: #''format_p:date:time:'';
at: 8 put: '' '';
at: 9 put: #''format_z:date:time:'';
at: 10 put: ''/'';
at: 11 put: #''format_f:date:time:'';
at: 12 put: ''/'';
at: 13 put: #''format_Y:date:time:'';
yourself);
yourself)'



So...with objects with long collections this method may be too much, but I just wanted to share it with you in case it could work as a first step. 

Best, 

Mariano


--
You received this message because you are subscribed to the Google Groups "VAST Community Forum" group.
To unsubscribe from this group and stop receiving emails from it, send an email to va-smalltalk...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/va-smalltalk/40d29e9c-46b7-486b-a9d8-78dab785c673n%40googlegroups.com.


--

Mariano Martinez Peck

Senior Software Engineer

 mp...@instantiations.com
 @MartinezPeck
 /mariano-martinez-peck
 instantiations.com
TwitterLinkedInVAST Community ForumGitHubYouTubepub.dev

thomas....@natural-software.eu

unread,
May 8, 2021, 11:41:44 AM5/8/21
to VAST Community Forum
I don't know about your specific requirement but I just want to share an approach that I found quite useful in difficult debugging situations.

The method markReadOnly: sets an object to call the method "attemptedROMStore:intoSlot:" when an instance variable of an object gets changed.

Thus, if you have an own object model of e.g. business objects you can use this approach to determine when someone changes an instance variable in an object in an unexpected way. Just implement this method in a subclass and you know when someone changes the object. If you do not want to disturb the flow in your program, then resetting markReadOnly in this method lets you write the new contents to an instance variable.

If "attemptedROMStore:intoSlot:" cannot be subclassed, you can always use an exception handler in order to get to the difficult location.

So for example:

| aObj assoc |
aObj :=Dictionary new.
aObj at: #A2 put: 'Hallo'.
assoc := aObj associationAt: #A2 ifAbsent:[].
assoc markReadOnly: true.
[
 aObj at: #A2 put: 'This will not be set into the object'.
] when: ExError do: [:sig |
sig arguments first = 'Store into read-only object' ifTrue: [
Transcript show: 'Read only object has been changed. Do perhaps a stack dump to see where the change comes from ??'; cr.
].
sig exitWith: nil.
].

And of course - this type of coding is for debugging purposes only. 
Reply all
Reply to author
Forward
0 new messages