[squeak-dev] The Inbox: Tools-LM.828.mcz

Tobias Pape Das.Linux at gmx.de
Tue Aug 14 06:43:27 UTC 2018


Hey

> On 14.08.2018, at 04:59, Eliot Miranda <eliot.miranda at gmail.com> wrote:
> 
> Hi,
> 
> regarding
> 
>> +    obj := parents at: obj ifAbsent: [nil].
>> -    obj := parents at: obj ifAbsent: [].
> 
> Please no.  One must know that the empty block evaluates to nil.  It is illiterate not to.  So the verbosity is bad; it implies uncertainty (“does the empty block evaluate to nil?  maybe not ‘cuz here it’s written explicitly”), it requires more typing, it’s ugly.  
> 
Oh come on :D
If I ask my students that have at least one year of Squeak experience, less than 5% would know that [] evaluates to nil.
Also, I think it is really better to be explicit and say "I want nil when there is nothing in there". 

I'd even rather say to forbid [] :P ;)


> Another thing one should know is that 
>     e ifTrue: [s]
> is the same as
>     e ifTrue: [s] ifFalse: []
> etc. ie, if e is false the value is nil.
> 

You know that I did not know that five years in into using Squeak (that is when I started implementing for my master's thesis)?
It's only obvious in hindsight. I had rather expected to

	e ifTrue: [s]  ===> false OR s

Which is an equally sensible variant.

I don't want wo argue that things are bad. but let's not go down that road and say One Must Know That ... :)


best regards
	-tobi


> 
> _,,,^..^,,,_ (phone)
> 
> On Aug 13, 2018, at 3:25 AM, commits at source.squeak.org wrote:
> 
>> A new version of Tools was added to project The Inbox:
>> http://source.squeak.org/inbox/Tools-LM.828.mcz
>> 
>> ==================== Summary ====================
>> 
>> Name: Tools-LM.828
>> Author: LM
>> Time: 13 August 2018, 1:25:54.504807 pm
>> UUID: 061511ca-729a-ce43-a08c-8057c24f7406
>> Ancestors: Tools-tcj.827
>> 
>> Added the ability to exclude specific objects from the  PointerFinder.
>> Improved the Explorer's "chase pointers" context menu to exclude the Explorer itself from the search (includes some meta-programming, not ideal, but certainly better than previously, ideas for improvement appreciated).
>> Changed the way the PointerExplorer displays references, it now states the associations name on the left, and the Objects hash is moved to the right, together with the objects displayString.
>> These changes make it much easier to understand how the objects are associated with each other and should make it easier to track down memory leaks.
>> 
>> =============== Diff against Tools-tcj.827 ===============
>> 
>> Item was changed:
>>  ----- Method: Inspector>>chasePointers (in category 'menu commands') -----
>>  chasePointers
>>      | selected  saved |
>>      self selectionIndex = 0 ifTrue: [^ self changed: #flash].
>>      selected := self selection.
>>      saved := self object.
>>      [self object: nil.
>>      (Smalltalk includesKey: #PointerFinder)
>>          ifTrue: [PointerFinder on: selected]
>>          ifFalse: [self inspectPointers]]
>>          ensure: [self object: saved]!
>> 
>> Item was changed:
>>  ----- Method: ObjectExplorer>>chasePointersForSelection (in category 'menus - actions') -----
>>  chasePointersForSelection
>>      
>> +    PointerFinder on: self object except: {self}, ObjectExplorerWrapper allInstances!
>> -    self flag: #tooMany. "mt: Note that we might want to ignore references caused by this tool."
>> -    self object chasePointers.!
>> 
>> Item was changed:
>>  ----- Method: PointerExplorer>>rootObject: (in category 'accessing') -----
>>  rootObject: anObject
>> 
>> +    self root key: 'root'.
>> -    self root key: anObject identityHash asString.
>>      super rootObject: anObject.!
>> 
>> Item was changed:
>>  ----- Method: PointerExplorerWrapper>>contents (in category 'accessing') -----
>>  contents
>>      "Return the wrappers with the objects holding references to item. Eldest objects come first, weak only referencers are at the end and have parentheses around their identity hash."
>> 
>>      | objects weakOnlyReferences |
>>      objects := self object inboundPointersExcluding: { self. self item. model }.
>>      weakOnlyReferences := OrderedCollection new.
>>      objects removeAllSuchThat: [ :each |
>>          each class == self class 
>>              or: [ each class == PointerExplorer
>>              or: [ (each isContext
>>                  and: [ (each objectClass: each receiver) == PointerExplorer ] )
>>              or: [ (each pointsOnlyWeaklyTo: self object)
>>                  ifTrue: [ weakOnlyReferences add: each. true ]
>>                  ifFalse: [ false ] ] ] ] ].
>>       ^(objects replace: [ :each |    
>> +        self class with: each name: (self nameForParent: each) model: self object ])
>> -        self class with: each name: each identityHash asString model: self object ])
>>          addAll: (weakOnlyReferences replace: [ :each |
>> +            (self class with: each name: '(', (self nameForParent: each), ')' model: self object)
>> -            (self class with: each name: '(', each identityHash asString, ')' model: self object)
>>                  weakOnly: true;
>>                  yourself ]);
>>          yourself!
>> 
>> Item was added:
>> + ----- Method: PointerExplorerWrapper>>explorerStringFor: (in category 'converting') -----
>> + explorerStringFor: anObject
>> + 
>> +    ^ anObject identityHash asString, ': ', (super explorerStringFor: anObject).!
>> 
>> Item was added:
>> + ----- Method: PointerExplorerWrapper>>memberNameFrom:to: (in category 'accessing') -----
>> + memberNameFrom: aParent to: aChild
>> + 
>> +    1 to: aParent class instSize do: [ :instVarIndex |
>> +        (aParent instVarAt: instVarIndex) = aChild
>> +            ifTrue: [ ^ '#', (aParent class instVarNameForIndex: instVarIndex)]].
>> +    "This also covers arrays"
>> +    1 to: aParent basicSize do: [ :index |
>> +        (aParent basicAt: index) = aChild
>> +            ifTrue: [^ index asString]].
>> +    ^ '???'!
>> 
>> Item was added:
>> + ----- Method: PointerExplorerWrapper>>nameForParent: (in category 'accessing') -----
>> + nameForParent: anObject
>> + 
>> +    ^  self memberNameFrom: anObject to: self object!
>> 
>> Item was changed:
>>  Model subclass: #PointerFinder
>> +    instanceVariableNames: 'goal parents toDo toDoNext hasGemStone pointerList objectList parentsSize todoSize depth pointerListIndex excludedObjects'
>> -    instanceVariableNames: 'goal parents toDo toDoNext hasGemStone pointerList objectList parentsSize todoSize depth pointerListIndex'
>>      classVariableNames: ''
>>      poolDictionaries: ''
>>      category: 'Tools-Debugger'!
>> 
>>  !PointerFinder commentStamp: '<historical>' prior: 0!
>>  I can search for reasons why a certain object isn't garbage collected.  I'm a quick port of a VisualWorks program written by Hans-Martin Mosner.  Call me as shown below.  I'll search for a path from a global variable to the given object, presenting it in a small morphic UI.
>> 
>>  Examples:
>>      PointerFinder on: self currentHand
>>      PointerFinder on: StandardSystemView someInstance
>> 
>>  Now, let's see why this image contains more HandMorphs as expected...
>> 
>>  HandMorph allInstancesDo: [:e | PointerFinder on: e]!
>> 
>> Item was added:
>> + ----- Method: PointerFinder class>>on:except: (in category 'instance creation') -----
>> + on: anObject except: aCollection
>> +    ^ self new 
>> +        goal: anObject;
>> +        excludedObjects: aCollection;
>> +        search;
>> +        open!
>> 
>> Item was changed:
>>  ----- Method: PointerFinder>>buildList (in category 'application') -----
>>  buildList
>>      | list obj parent object key |
>>      list := OrderedCollection new.
>>      obj := goal.
>>      
>>      [list addFirst: obj.
>> +    obj := parents at: obj ifAbsent: [nil].
>> -    obj := parents at: obj ifAbsent: [].
>>      obj == nil] whileFalse.
>>      list removeFirst.
>>      parent := Smalltalk.
>>      objectList := OrderedCollection new.
>>      pointerList := OrderedCollection new.
>>      [list isEmpty]
>>          whileFalse: 
>>              [object := list removeFirst.
>>              key := nil.
>>              (parent isKindOf: Dictionary)
>>                  ifTrue: [list size >= 2
>>                          ifTrue: 
>>                              [key := parent keyAtValue: list second ifAbsent: [].
>>                              key == nil
>>                                  ifFalse: 
>>                                      [object := list removeFirst; removeFirst.
>>                                      pointerList add: key printString , ' -> ' , object class name]]].
>>              key == nil
>>                  ifTrue: 
>>                      [parent class == object ifTrue: [key := 'CLASS'].
>>                      key == nil ifTrue: [1 to: parent class instSize do: [:i | key == nil ifTrue: [(parent instVarAt: i)
>>                                      == object ifTrue: [key := parent class instVarNameForIndex: i]]]].
>>                      key == nil ifTrue: [parent isCompiledCode ifTrue: [key := 'literals?']].
>>                      key == nil ifTrue: [1 to: parent basicSize do: [:i | key == nil ifTrue: [(parent basicAt: i)
>>                                      == object ifTrue: [key := i printString]]]].
>>                      key == nil ifTrue: [(parent isMorph and: [object isKindOf: Array]) ifTrue: [key := 'submorphs?']].
>>                      key == nil ifTrue: [key := '???'].
>>                      pointerList add: key , ': ' , object class name, (object isMorph ifTrue: [' (', object identityHash asString, ')'] ifFalse: [ String empty ]) ].
>>              objectList add: object.
>>              parent := object]!
>> 
>> Item was added:
>> + ----- Method: PointerFinder>>excludedObjects (in category 'accessing') -----
>> + excludedObjects
>> + 
>> +    ^ excludedObjects ifNil: [excludedObjects := OrderedCollection new]!
>> 
>> Item was added:
>> + ----- Method: PointerFinder>>excludedObjects: (in category 'accessing') -----
>> + excludedObjects: aCollection
>> + 
>> +    excludedObjects := aCollection!
>> 
>> Item was changed:
>>  ----- Method: PointerFinder>>followObject: (in category 'application') -----
>>  followObject: anObject
>> + 
>> +    (self excludedObjects includes: anObject)
>> +        ifTrue: [^ false].
>>      anObject outboundPointersDo: [:ea |
>>          (self follow: ea from: anObject)
>>              ifTrue: [^ true]].
>>      ^ false!
>> 
>> Item was changed:
>>  ----- Method: PointerFinder>>initialize (in category 'application') -----
>>  initialize
>>      parents := IdentityDictionary new: 20000.
>>      parents at: Smalltalk put: nil.
>>      parents at: Processor put: nil.
>>      parents at: self put: nil.
>> 
>>      toDo := OrderedCollection new: 5000.
>>      toDo add: Smalltalk.
>> +    toDoNext := OrderedCollection new: 5000.!
>> -    toDoNext := OrderedCollection new: 5000!
>> 
>> 
> 



More information about the Squeak-dev mailing list