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".
> 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
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 ... :)
>
> _,,,^..^,,,_ (phone)
>
> On Aug 13, 2018, at 3:25 AM,
[hidden email] 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!
>>
>>
>