So far, we have seen two global methods for printing to the screen:
putln for strings and println for objects in general. These global
methods, as well as they’re companions puts and print (which do
not end in a newline), all delegate to the standard output stream
object $stdout. Now we’re going to discuss how stream objects work
and which ones come built in to Latitude.
Latitude comes with three built-in global stream objects: $stdout,
$stdin, and $stderr. All three of these names are dynamically
scoped to make it easy for programmers to locally override them.
do {
;; Run someOperation, but block any textual output.
$stdout := Stream null.
$stderr := Stream null.
someOperation.
}.
Since the output streams are dynamic variables, someOperation will
see the new values for them: a null stream which ignores all text
written to it, like /dev/null.
Stream objects provide several ways of outputting information. We have already discussed the four main output functions, but to summarize
| Name | Accepts | Newline? |
|---|---|---|
puts |
Strings only | No |
putln |
Strings only | Yes |
print |
Any objects | No |
println |
Any objects | Yes |
Unlike output functions, input functions always operate on strings.1
| Name | Returns | Reads |
|---|---|---|
read |
String | One character |
readln |
String | Full line |
To check if a stream is designated for input or output, send it the
in? or out? message. Streams can be but are not necessarily
designated for both; for instance, the null stream from the example
above is designated for both input and output. Of course, $stdin is
only for input, and $stdout and $stderr are only for output.
To check whether a stream has hit its end, send it the eof? message.
Streams are closed with the close message, although as we have seen
in the previous chapter, it is more common to use closeAfter to
protect the stream in the case of an error.
Constructing a file stream is done with the Stream open method.
file := Stream open ("myfile.txt", "r") closeAfter {
;; Do some work ...
}.
The first argument to Stream open is, of course, the file name. The
second argument specifies the mode. The mode should be either r or
w, respectively for read and write. You may append a b to the mode
to specify that it is a binary file; this may cause the operating
system to treat new lines differently. So the four valid mode strings
are: r, w, rb, wb.
Output stream objects also provide a printf method, for formatted
printing. The stream printf method takes a formatter as its first
argument, followed by any arguments to be forwarded to the formatter.
The formatter can be any procedure-like object: that is, any object
which responds to the call message.2 However, most likely we
will be using the FormatString object from the 'format module,
which was built for this purpose.
use 'format importAllSigils.
$stdout puts: "Name: ".
yourName := $stdin readln.
$stdout puts: "Age: ".
yourAge := { $stdin readln toInt. } catch (err InputError) do { "<unknown>". }.
$stdout printf: ~fmt "Hello, ~A! (age ~A)", yourName, yourAge.
The ~fmt bit begins a sigil expression, which in this case is simply
a concise shortcut to constructing a FormatString object. The format
string object supports the following directives.
~S consumes one argument and calls toString on it.~A consumes one argument and calls pretty on it.~~ prints a literal tilde.In this case, we use the second variant. pretty delegates to
toString in most cases; for strings, pretty will return the string
itself, whereas toString will place quotes around it. In general,
toString should produce relatively machine-readable output, whereas
pretty is free to make its output more user-friendly.
Remember that printf simply sends the call message to the
formatting object. So if you wish to format a string but not print it,
you may send call directly to the object to get a formatted string
as the return value.
use 'format importAllSigils.
message := ~fmt "Hello, ~A!" call ("John Doe"). ; ==> Hello, John Doe!
You have now had an introduction to most of the Stream object
functionality, as well as construction of formatted strings. In the
next chapter, we’ll formally discuss modules and Latitude’s import
system.
[up]
[prev - Advanced Flow Control]
[next - Modules]
1 Note that read
may behave strangely at the REPL. This is because the REPL shares the
same input stream and uses readln internally, so after you read
one character, the REPL will immediately consume the rest of the line
and try to run it as a command.
2 By convention, the
parent of all procedure-like objects is the global Proc object. You
can construct these objects explicitly from a method with proc { ...
}. Additionally, methods themselves are (indirect) subobjects of
Proc. Likewise, continuation objects are also subobjects of Proc.