"Clean" closure with no references to anything from outer scopes. A clean closure has outerContext = nil and copiedValues = empty Array.
"Copying" closure that copies immutable values from outer scopes when the closure is created. A copying closure has outerContext = nil and copiedValues = Object or Array.
"Full" closure that retains a reference to the next outer scope. A full closure has outerContext ~= nil and copiedValues = nil.
As an optimization, copiedValues holds the single copied value if there is exactly one, or an Array of values if there is more than one. Note that if there is a single copied value, the value being copied can be nil, so testing for nil in copiedValues is not a reliable means of classifying closures. The way to check whether a closure has copied values is to ask its method whether numCopiedValues > 0.
BlockClosure Class Comments
Now if we use a stream for the Smalltalk keys we can avoid an iteration method. With whileFalse: that is inlined the block itself will be inlined.
aReadStream := ReadStream on: Smalltalk keys asArray.
aWriteStream := WriteStream on: String new.
[aReadStream atEnd] whileFalse: [aWriteStream nextPutAll: a ReadStream next].