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

Eliot Miranda eliot.miranda at gmail.com
Tue Aug 14 07:50:11 UTC 2018


Hi Tobias,

> On Aug 13, 2018, at 11:43 PM, Tobias Pape <Das.Linux at gmx.de> wrote:
> 
> 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 ;)

That way leads to American English...or Newspeak (Orwell) ;-)

Seriously, there is a flaw in the teaching if your figures are right.  Literacy is important.  Brevity is important. Idiom is important.  And knowing what the basic elements of the language are is important.  That [] value == nil is true is important.

>> 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)?

Did you never read the definitions for ifTrue: and ifFalse: ?

> 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 ... :)

But yes, one /should/ know that.  The core classes should be read.  If you want to raise a generation of JavaScripters then sure, ignore literacy.  But if you want to raise a generation that can appreciate great, carefully considered design, educate them to think and to read and write well.  Everything else is Ebonics and the Prussian Model.

> 
> 
> 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