I think it's fair to say that #<< *is* a bug.
There does not seem to be any coherent description of what it means.
It's overloaded to mean *either* #nextPut: *or* #nextPutAll: *or*
something else, in some confusing ways.
CommandLineHandler�������������������� #nextPutAll: (sent somewhere else)
Integer������������������������������������������ left shift (someone has been smoking too much C++)
NonInteractiveTranscript�������� #show: = locked #print:
SocketStream�������������������������������� #putOn: (which may itself act like
�������������������������������������������������������� #nextPut:, #nextPutAll:, #print,
�������������������������������������������������������� put elements sans separators, or
�������������������������������������������������������� something else)
Stream�������������������������������������������� #putOn: (see above)
WriteStream���������������������������������� either #nextPutAll: or #putOn:
Transcript������������������������������������ #show: = locked #print:
ThreadSafeTranscript���������������� #show: = locked #print:
VTermOutputDriver���������������������� #putOn:
VTermOutputDriver2�������������������� #asString then #nextPutAll:
ZnEncodedWriteStream���������������� #nextPutAll:
ZnHtmlOutputStream�������������������� #asString then #nextPutAll:
SequenceableCollection class #streamContents:
As was once said about PL/I, #<< fills a much-needed gap.
When I see #print:, or #nextPut:, or #nextPutAll:, I know
what to expect.�� When I see #putOn:, I have in general no
idea what will happen.�� And when I see << it is worse.
One point of << is to imitate C++'s composition of outputs.
That might work, too, if only there were some agreement
about what #nextPutAll: returns.�� There is not.�� It might
return the receiver.�� It might return some other stream
related to the receiver.�� It might even return the collection
argument.�� So when you see
��a << b << c
in general you not only do not have a clue what (a) is going
to do with (b) but you have no idea what object the message
<< c will be sent to.
Now let's see if we can puzzle out what
Array streamContents: [ :s | s << 10 << '10' << #(10 '10') ]
does.
The output will be going to a WriteStream.
aWriteStream << anInteger
is not, but is like, aWriteStream print: anInteger.
So we add $1 and $0.
aWriteStream << aString
reduces to aWriteStream nextPutAll: aString.
So we add $1 and $0.
aWriteStream on anArray << anotherArray
reduces to aWriteStream nextPutAll: anotherArray.
So we add 10 and '10'.
Thus the result we get is
#($1 $0 $1 $0 10 '10').
What result we should *expect* from this muddle I cannot say.
If, on the other hand, you wrote explicitly
Array streamContents: [:stream |
�� stream print: 10; nextPutAll: '10'; nextPutAll: #(10 '10')]
you would have an easy time figuring out what to expect.
By the way, there is no standard definition of #show:, but in
other Smalltalk systems it's usually a variant of #nextPutAll:,
not a variant of #print:.�� There's no denying that locked output
is useful to have, but #show: is not perhaps the best name for it.