September 23, 2023

Textual representation of objects (print-strings)


In the previous section I referred briefly to the textual representation of objects, this is an aspect of Smalltalk that causes some confusion amongst students.

Any object can be evaluated by typing a variable or a literal (strings, numbers etc), in the evaluation pane of a Workspace, selecting it and then clicking the Evaluate selection button. In LearningWorks there is a class LwWorkspace that is used to construct a Workspace page. It has an instance variable messageAnswerObject and a message in its instance protocol called printIt. Here is the header followed by a small fragment of code taken from the method body.

   "Evaluate, obtain the object result of evaluation
   and display the result   when check box is true ..."
   "code omitted"
   resultTextModel show: (self messageAnswerObject
   printString, (String with: Character cr))
    "code omitted"

This code results in the message answer object's textual representation being displayed in the Display pane beneath. The text that you see on the screen is a representation of the string (also known as a print-string) resulting from a printString message being sent to the message answer object. All objects inherit printString from Object.

   "Answer a String whose characters are a description
   of the receiver."
     | aStream |
    aStream := WriteStream on: (String new: 16).
    self printOn: aStream.
    ^aStream contents

All objects have a textual representation. printIt reuses printString which in turn reuses printOn: also found in the instance protocol of Object.

printOn: aStream
  "Append to the argument aStream a sequence of
   characters that describes   the receiver."
    | title |
    title := self class name.
    aStream nextPutAll:((title at: 1) isVowel
       ifTrue: ['an ']
       ifFalse: ['a ']).
    aStream print: self class

It is this implementation of printOn: that results in the default representation of a message answer. e.g.

an Account

N.B. Smalltalk will not write a Account, but it will write a Painting instead of
an Painting.

However, printOn: is often overridden in order to provide other objects with a textual representation that will inform the user of that object's state. This is the case with an instance of Frog. The following method can be found in the abstract superclass Amphibian.

printOn: aStream
  "Create a description of the receiver on aStream (an
   instance of   Stream). Answer the receiver."
    aStream nextPutAll: 'An instance of class '.
    aStream nextPutAll: self class printString.
    aStream nextPutAll: ' (position '.
    self position printOn: aStream.
    aStream nextPutAll: ', '.
    aStream nextPutAll: ' colour '.
    self colour printOn: aStream.
    aStream nextPutAll: ')'

Evaluating kermit, or whatever variable you have assigned to a Frog instance, produces something like

An instance of class Frog (position 1, colour Green)

A string object is simply an array of Character objects. It can be referenced directly by writing something like 'john'. In Smalltalk a character object is specified by prefixing the character with a $.
Therefore, 'john' is a string object consisting of the four Character instances $j $o $h $n.

It is true to say that the textual representation of a literal (string, number, symbol) can be used as a reference to an object. But the same cannot be said for non-literals. While the textual representation of 'account', which is also 'account', can be used in the evaluation pane to reference a string, you could not use an Account to reference an Account object.

String objects respond to messages such as:
asUppercase, asLowercase, dropVowels.
They return a string object, but that object is not the same object as the receiver. The receiver remains unchanged. If you evaluate

myString := 'john'.
myString dropVowels

The message answer will be the string object 'jhn'. Inspection of myString will confirm this still references the string 'john'.

Now if you try an evaluation of:

myString = 'john' "Answers true"
myString == 'john' "Answers false"

The = message is a test for state, but == is a test for identity. The latter returns false because the receiver string 'john', referenced by myString, is not the same string as the argument 'john'. The system has created two strings, albeit with the same state.

Note that if a string contains a 'character then it must be accompanied by another ' e.g.

'john''s website'
"and not"
'john's website'

Strings are not immutable, they can be changed.

poetString := 'Keats'.
poetString at: 1 put: $Y

I will look at the String class again when discussing collections.

Go here for some print-string questions and answers.


Next page » Precedence

Previous page « Object-interaction diagrams
































































Up to top of page