Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

Console IO

There are, in general, four ways to write to the console in Tango:

  • with the C printf (not recommended, only for tracing down problems with the runtime itself).
  • Cout/Cerr, having the fewest dependencies and thus resulting in the smallest binaries, but lacking formatted output.
  • Stdout/Stderr, the standard way for formatted console output. This is Tango's printf.
  • Trace, the synchronized version of Stderr, for outputting from several threads at the same time. This helps when debugging.

source:/trunk/doc/images/objdia.tango.console.png

This object diagram shows which type the console accessor objects are.

Cout, Cerr

The way to display text on the console with the fewest dependencies is via either Cout or Cerr. These are predefined entities within tango.io.Console, which accept char[] and direct them to the appropriate output device:

import tango.io.Console;

Cout ("now is the time for all good men to come to the aid of their country").newline;

Note that there’s a newline modifier appended. Line breaks may be embedded within the text also, using the traditional \n syntax. Console output is buffered: without a newline, the text would not be sent to the destination immediately. Where output line breaks are inappropriate, immediate flushing may be achieved as follows:

Cout ("now is the time for all good men to come to the aid of their country").flush;

Console methods return a chaining reference, to support the following style:

Char[] people = "women";

Cout ("now is the time for all good ") (people) (" to come to the aid of their country").newline;

Note that the arguments are all char[] and are emitted in a simple left-to-right order. Each argument is passed by itself, and appended to the console output. A short-hand notation for flush is a null argument, like so:

Cout ("What is your name? ") ();

Object references may also be passed to Cout:

auto o = new Object;

Cout ("the name of Object is ")(o).newline;

Console exposes the underlying stream instances in order to permit more expressive usage. For example, a shortcut for copying a text file to the console is as follows:

auto file = new FileConduit ("myfile");

Cout.stream.copy (file);

Similarly, we could copy the raw content from a website (using path /index.html):

auto site = new SocketConduit;
site.connect (new InternetAddress("myWebSite")).write ("GET /index.html HTTP/1.0\n\n");

Cout.stream.copy (site);

Console input is handled in a similar manner, but using the predefined entity Cin, rather than Cout. Tango waits for some input to be available, and returns all of it to the caller. With interactive usage, this is typically one line of input (relayed when the CR key is pressed, for instance). For instance:

Cout ("What is your name? ") ();
auto name = Cin.get();

Cout ("Hello ") (name).newline;

Cin

Cin is the application's input stream. This stream, when coming from the console user's input, is always line oriented. This means, the OS always waits for the user to press the <Enter> key and then passes the whole line to the application. If the application wants to poll the keyboard for a key pressed or some special key states, the application has to use the C functions from tango.stdc.

Cin can read a line of input with readln, which returns a slice of the internal buffer, or with copyln, which returns a copy.

When redirection is applied, Cin will relay large quantities of the redirected input back to the caller for each invocation. One way to split redirected input into lines of text would be to apply a stream-oriented iterator:

import tango.text.stream.LineIterator;

foreach (line; new LineIterator!(char)(Cin.stream))
         // do something with each line

As you can see, this illustrates the console input being used purely as a streaming input source. Later releases of Tango may embed this type of functionality if users deem it suitable.

All console-based IO is strictly UTF-8 only. This is to ensure platform independence, and to ensure console redirection is handled correctly in all cases.

Console Exceptions

IO exceptions are thrown when the underlying OS determines that an error occurred. This might occur if, say, redirection ran into a problem with a remote file.

Stdout, Stderr

Stdout is to Tango what System.out.printf is to Java or printf to C: the standard way of printing formatted output to the console.

Stdout is a general-purpose formatter, sitting atop of Cout. There’s also a Stderr, tied to Cerr; both are predefined within the tango.io.Stdout module. While Cout handles char[] only, Stdout supports a wide range of types, converting from native representation to text for display purposes, and converting text represented in UTF-16 or UTF-32.

The core functionality is provided by tango.text.convert.Format, and exposed here via a number of convenience methods.

For usage of the format specifiers see ChapterConversions#Layoutsformatstring

These methods return a chaining reference (like much of the library does) and generally accept multiple arguments in the conventional vararg style. For example, chaining calls look like this:

import tango.io.Stdout;

Stdout (10) (" green bottles, sitting on the wall").newline;

Whereas a vararg call looks like this:

Stdout.format ("{} green bottles, sitting on the wall", 10).newline;

There is also a variant to imply a .newline:

Stdout.formatln ("{} green bottles, sitting on the wall", 10);

Flushing the output without a line break is similar to Cout, using either .flush, or an empty set of parentheses:

Stdout (10) (" green bottles, sitting on the wall") ();

Like Cout and Cerr, Stdout and Stderr expose the underlying OutputStream, which may be used directly where appropriate. Revisiting a Cout example:

auto file = new FileConduit ("myfile");
Stdout.stream.copy (file);

Or, to sidestep type-conversion and append text directly to the underlying buffer:

Stderr.stream.write ("my error message");

See the documentation on tango.text.convert.Format for specifics on various formatting options. Also note that the Stdout functionality is exposed as a class named Print, which can be used to bind the same interface to a stream other than those tied to Cout and Cerr (such as a file, or network connection).

Stdout also exposes the Layout instance in use, so it can be invoked directly. For example, it can sometimes be useful to construct an array of the formatted output:

auto string = Stdout.layout.sprint ("{} green bottles", 10);

It is also possible to replace the attached Layout instance, which can be used to configure Stdout/Stderr with a locale-specific Layout handler. This permits great flexibility over settings for regional formatting of currency, decimal and numeric representations, and date/time formatting.

Stdout Exceptions

Formatting exceptions may be raised if an argument to the formatter cannot be processed.

Trace

Trace is not a part of tango.io, but it is related to this chapter.

One often needs output when tracing the execution of a program. Stdout/Stderr/Cout/Cerr are not suitable for this, as they are not thread safe. When outputting concurrently from several different threads, use Trace, which is synchronized for this purpose.

import tango.util.log.Trace;

void f(){
   // ...
   int idx = someCalc();
   Trace.formatln ("{}@{} : My variable={}", __FILE__, __LINE__, idx );
   // ...
}

C printf

printf is available, as are all standard C functions. It can be used via the tango.stdc.stdio module.

import tango.stdc.stdio;

printf ("at pos %lld, %.*s \n", __LINE__, __FILE__ );

At the moment D arrays are represented as a length and a pointer to data. Knowing this internal representation, printf can be used to print D strings using the "%.*s" format specifier. But it was announced that this representation might change, so this might break in the future.

Special care must be taken to use the correct size specifier for printf. E.g. __LINE__ in D is of type long, so in this case "%lld" is needed.

Caution: the use of printf is not recommended. Use it only for low level debugging and when you know what you're doing.