> On 05 Feb 2015, at 15:44, Nicolai Hess <nicolaih...@web.de> wrote: > > 2015-02-02 3:03 GMT+01:00 Eliot Miranda <eliot.mira...@gmail.com>: > > > On Sun, Feb 1, 2015 at 3:39 AM, Nicolai Hess <nicolaih...@web.de> wrote: > > > 2015-02-01 10:52 GMT+01:00 Ben Coman <b...@openinworld.com>: > > Looking into Image locking problems [1] caused by a recursive array such as > this... > > literalArray := #( 1 2 3 ). > literalArray at: 3 put: literalArray. > > I find that "literalArray printString" locks the image due to Array>>printOn: > use of the recursive #shouldBePrintedAsLiteral method. Now its implementation > is identical to #isLiteral and indeed "literalArray isLiteral" also locks the > Image. So comparing implementors of #isLiteral... > > > > Squeak uses a Set to store all visited elements for shouldBePrintedAsLiteral > and this protects against the recursive loop. > > shouldBePrintedAsLiteralVisiting: aSet > self class == Array ifFalse: > [^false]. > (aSet includes: self) ifTrue: > [^false]. > aSet add: self. > ^self allSatisfy: [:each | each shouldBePrintedAsLiteralVisiting: aSet] > > > isn't there a common pattern to handle this kind of potential endless > recursion? > > At Cadence we fixed it thus: > > Object>>shouldBePrintedAsLiteral > > ^self isLiteral > > Array>>shouldBePrintedAsLiteral > > ^self class == Array > and: [self shouldBePrintedAsLiteralVisiting: (IdentitySet new: 8)] > > Object>>shouldBePrintedAsLiteralVisiting: aSet > > ^self isLiteral > > Array>>shouldBePrintedAsLiteralVisiting: aSet > self class == Array ifFalse: > [^false]. > (aSet includes: self) ifTrue: > [^false]. > aSet add: self. > ^self allSatisfy: [:each | each shouldBePrintedAsLiteralVisiting: aSet] > > > Is there something more "generic". Something we can use for any object > tracing. > Isn't there something the GC uses? The GC obviously does not fall into this > loop. > (It flags visited objects, but there is nothing exposed that can be used > at the image level?) > How do ImageSegment or Fuel work with recursive structures?
In Moose there is DeepTraverser which does something similar it seems. FUEL & STON do this too. > Nicolai > > > > Object>>isLiteral ^false > Boolean>>isLiteral ^true > Character>>isLiteral ^true > Integer>>isLiteral ^true > String>>isLiteral ^true > UndefinedObject>>isLiteral ^true > > ByteArray>>isLiteral ^self class == ByteArray > Float>>isLiteral ^self isFinite "^(self - self) = 0.0" > ScaledDecimal>>isLiteral ^denominator = 1 or: [(10 raisedTo: > scale)\\denominator = 0] > > Array>>isLiteral ^self class == Array and: [self allSatisfy: > [:each | each isLiteral]] > > ...I find most are very basic (might even say deterministic), with the > recursion of Array>>isLiteral seeming an annomaly. Also, the big IF > condition in Array>>printOn: smells like a design decision being made at > runtime (Valloud AMCOS p12). > > Array>>printOn: aStream > self shouldBePrintedAsLiteral ifTrue: [self printAsLiteralFormOn: > aStream. ^ self]. > self isSelfEvaluating ifTrue: [self printAsSelfEvaluatingFormOn: > aStream. ^ self]. > super printOn: aStream > > Flipping between two printString formats seems like selecting between two > class types. Indeed, if we had a LiteralArray class, there would be no need > for its printOn: to recursively search to determine its form, thus allowing > #printStringLimitedTo: to do its thing to protect against infinite recursion. > > Also, instead of a recursive Array>>isLiteral we'd have something like > LiteralArray>>isLiteral ^true > Array>>isLiteral ^false > which seems to align much better with the pattern of the other #isLiteral > implementors. > > I notice there is both RBArrayNode and RBLiteralArrayNode. > > So what are the wider concerns that might apply? > (In particular, I'm not sure how the #isSelfEvaluating (which is also > recursive) fits into the big picture) > > cheers -ben > > [1] https://www.mail-archive.com/pharo-dev@lists.pharo.org/msg25156.html > > > > > -- > best, > Eliot