Console
The global console object is available in every program without an import. Every method takes any
number of arguments of any type, converts each to a string, joins them with a single space, and
writes the result followed by a newline.
console.log("Hello, World!");console.log("x =", 42, "ok?", true);console.log("Zeus supports UTF-8 π");Hello, World!x = 42 ok? trueZeus supports UTF-8 πMethods
All five methods behave identically except for where they write:
| Method | Stream |
|---|---|
console.log | standard output |
console.info | standard output |
console.debug | standard output |
console.warn | standard error |
console.error | standard error |
console.log("normal output"); // stdoutconsole.info("informational"); // stdoutconsole.debug("debug detail"); // stdoutconsole.warn("heads up"); // stderrconsole.error("went wrong"); // stderrAny number of arguments
Each argument is converted to a string and the results are joined by a single space. Calling a method with no arguments prints an empty line.
console.log("a", "b", "c"); // a b cconsole.log(1, 2, 3); // 1 2 3console.log(); // (blank line)Any value prints
You never have to convert a value before logging it β numbers, booleans, null, objects, and arrays
all print directly.
console.log(42); // 42console.log(3.14); // 3.14console.log(true); // trueconsole.log(null); // nullObjects and arrays
An object with no custom toString prints its class name and fields; an array prints its elements.
This works recursively β nested objects and arrays are expanded, and string values are quoted inside
them.
class Point { x: i32; y: i32; constructor(x: i32, y: i32) { this.x = x; this.y = y; }}
class Person { name: string; age: i32; constructor(name: string, age: i32) { this.name = name; this.age = age; }}
console.log(new Point(1, 2)); // Point { x: 1, y: 2 }console.log(new Person("bob", 30)); // Person { name: "bob", age: 30 }console.log([1, 2, 3]); // [1, 2, 3]console.log(["a", "b"]); // ["a", "b"]console.log([new Point(1, 2), new Point(3, 4)]);// [Point { x: 1, y: 2 }, Point { x: 3, y: 4 }]Inherited fields are included (base fields first), and deeply self-referential graphs are printed to a bounded depth so cyclic data never loops forever.
Customizing output with toString
Give a class a public toString(): string method to control exactly how it prints. Your toString
is used everywhere a value becomes a string: console.log, string concatenation, template strings,
and an explicit .toString() call.
class Money { cents: i32; constructor(cents: i32) { this.cents = cents; } toString(): string { return "$" + this.cents; }}
let price: Money = new Money(500);console.log(price); // $500console.log("total:", price); // total: $500console.log(`price is ${price}`); // price is $500A custom toString is honored for nested values too β a field whose type defines toString
renders through it instead of structurally:
class Cart { item: Money; qty: i32; constructor(item: Money) { this.item = item; this.qty = 3; }}
console.log(new Cart(new Money(500))); // Cart { item: $500, qty: 3 }toString on any value
Because reflection provides a default, toString() is callable on every value β override it or
not:
console.log((new Point(1, 2)).toString()); // Point { x: 1, y: 2 } (default)console.log((new Money(500)).toString()); // $500 (custom)console.log([1, 2, 3].toString()); // [1, 2, 3]console.log((42).toString()); // 42Byte arrays
A u8[] is Zeusβs raw byte string, so it decodes to text rather than printing as a list of numbers:
let bytes: u8[] = new u8[];bytes[0] = 'H';bytes[1] = 'i';
console.log(bytes); // Hi