Skip to main content

IO

The IO module groups together everything related to input and output: writing to the console, reading from the keyboard, reporting errors and working with files on disk.

IO itself is a static container; you never construct an IO instance. Instead, you use one of its inner static classes:

  • stdout — standard output stream
  • stderr — standard error stream
  • stdin — standard input stream
  • File — file system operations

All members of IO and its sub-classes are static. They cannot be instantiated.

IO(); // error: IO is a static class, cannot take instance
stdout(); // error: stdout is a static class, cannot take instance
File(); // error: File is a static class, cannot take instance

stdout

Writes text to the standard output stream (the terminal, by default).

Static methods

MethodSignatureReturn TypeDescription
writewrite(text : string)nullWrites text to standard output without a trailing newline.
writelnwriteln(text : string)nullWrites text to standard output with a trailing newline.
IO.stdout.write("Hello, ");
IO.stdout.writeln("world!");
// Output:
// Hello, world!

stderr

Writes text to the standard error stream. Behaves exactly like stdout, but the output is sent to the error channel and is typically displayed in red by terminals/IDEs.

Static methods

MethodSignatureReturn TypeDescription
writewrite(text : string)nullWrites text to standard error without a trailing newline.
writelnwriteln(text : string)nullWrites text to standard error with a trailing newline.
IO.stderr.writeln("Something went wrong!");

stdin

Reads input from the standard input stream (the keyboard, by default).

Static methods

MethodSignatureReturn TypeDescription
readlnreadln()stringReads a single line of text from standard input (up to the next newline). The newline character is stripped.
readKeyreadKey()charReads a single character (one byte) from standard input.
IO.stdout.write("What is your name? ");
let name = IO.stdin.readln();
IO.stdout.writeln("Hello, " + name + "!");
IO.stdout.write("Press any key to continue... ");
let k = IO.stdin.readKey();
IO.stdout.writeln("");
IO.stdout.writeln("You pressed: " + k);

If the underlying stream throws while reading, a runtime error is raised.

File

Static helpers for reading, writing and deleting files on disk.

All paths can be either absolute or relative. Relative paths are resolved against the current working directory of the running interpreter, so "data.txt" and "./data.txt" both refer to a file next to where the program was started.

Static methods

MethodSignatureReturn TypeDescription
readread(path : string)stringReads the entire content of the file at path and returns it as a string.
writewrite(path : string, content : string)nullWrites content to the file at path, creating the file if missing and truncating it if it already exists.
appendappend(path : string, content : string)nullAppends content to the end of the file at path. Creates the file if it does not exist.
deletedelete(path : string)nullDeletes the file (or empty directory) at path.

Examples

Reading a file:

let text = IO.File.read("notes.txt");
IO.stdout.writeln(text);

Writing a file (overwrites existing content):

IO.File.write("output.txt", "Hello, file!\n");

Appending to a file:

IO.File.append("log.txt", "[INFO] Application started\n");
IO.File.append("log.txt", "[INFO] Loading config...\n");

Deleting a file:

IO.File.delete("output.txt");

Errors

File operations raise a runtime error in the following cases. You can catch them with a try / catch block.

MethodPossible errors
readFile not found, access denied, other I/O failure.
writeParent directory does not exist, access denied, other I/O failure.
appendParent directory does not exist, access denied, other I/O failure.
deleteFile does not exist, directory is not empty, access denied, other I/O failure.
try do
let data = IO.File.read("missing.txt");
end catch (err) do
IO.stderr.writeln("Could not read file: " + err);
end

Directory

Static helpers for creating, deleting, listing and querying directories on disk. Also provides convenient accessors for special system directories (home, desktop, downloads, temp, etc.).

All paths can be either absolute or relative. Relative paths are resolved against the current working directory of the running interpreter.

Static methods

Directory Operations

MethodSignatureReturn TypeDescription
createcreate(path : string)nullCreates a single directory at path. Fails if parent directory does not exist.
createAllcreateAll(path : string)nullCreates a directory and all missing parent directories at path (like mkdir -p).
existsexists(path : string)booleanReturns true if a directory exists at path, false otherwise.
deletedelete(path : string)nullDeletes the directory at path. Fails if the directory is not empty.
listlist(path : string)arrayReturns an array of file/directory names in the directory at path.

Special Directory Accessors

These methods return the path to system directories and require no arguments:

MethodReturn TypeDescription
getHomestringReturns the path to the user's home directory (e.g. /home/username on Linux).
getCurrentstringReturns the current working directory where the program is running.
getTempstringReturns the system temporary directory (e.g. /tmp on Unix, %TEMP% on Windows).
getDesktopstringReturns the path to the user's Desktop folder.
getDocumentsstringReturns the path to the user's Documents folder.
getDownloadsstringReturns the path to the user's Downloads folder.
getAppDatastringReturns the path to application data directory (OS-specific).
getConfigstringReturns the path to user config directory (OS-specific).
getCachestringReturns the path to user cache directory (OS-specific).

Examples

Creating directories

// Create a single directory (fails if parent doesn't exist)
IO.Directory.create("mydir");

// Create nested directories (creates parents as needed)
IO.Directory.createAll("path/to/my/nested/dir");

Checking if a directory exists

if IO.Directory.exists("mydir") then
IO.stdout.writeln("Directory exists!");
else
IO.stdout.writeln("Directory does not exist");
end

Listing directory contents

let files = IO.Directory.list(".");
for var i = 0; i < files.size(); i = i + 1 do
IO.stdout.writeln(files.get(i));
end

Deleting a directory

// Only works if directory is empty
IO.Directory.delete("mydir");

Getting special directories

// Get home directory
let home = IO.Directory.getHome();
IO.stdout.writeln("Home: " + home);

// Get current working directory
let cwd = IO.Directory.getCurrent();
IO.stdout.writeln("Current: " + cwd);

// Get downloads folder
let downloads = IO.Directory.getDownloads();
IO.stdout.writeln("Downloads: " + downloads);

// Get temporary directory
let temp = IO.Directory.getTemp();
IO.stdout.writeln("Temp: " + temp);

// Get application data directory
let appData = IO.Directory.getAppData();
IO.stdout.writeln("AppData: " + appData);

Practical example: Create a project structure

let projectRoot = "my-project";

// Create the root directory and all subdirectories
IO.Directory.createAll(projectRoot + "/src");
IO.Directory.createAll(projectRoot + "/tests");
IO.Directory.createAll(projectRoot + "/docs");
IO.Directory.createAll(projectRoot + "/build");

IO.stdout.writeln("Project structure created!");

Practical example: Working with downloads

let downloads = IO.Directory.getDownloads();
let files = IO.Directory.list(downloads);

IO.stdout.writeln("Files in Downloads:");
for var i = 0; i < files.size(); i = i + 1 do
IO.stdout.writeln(" - " + files.get(i));
end

Errors

Directory operations raise a runtime error in the following cases. You can catch them with a try / catch block.

MethodPossible errors
createParent directory does not exist, access denied, path already exists.
createAllAccess denied, other I/O failure.
existsAccess denied, invalid path.
deleteDirectory does not exist, directory is not empty, access denied.
listDirectory does not exist, path is not a directory, access denied.
try do
IO.Directory.list("nonexistent");
end catch (err) do
IO.stderr.writeln("Could not list directory: " + err);
end

Platform-Specific Behavior

The special directory accessors (getAppData, getCache, getConfig) return different paths depending on the operating system:

MethodWindowsmacOSLinux
getAppData%APPDATA%~/Library/Application Support$XDG_DATA_HOME or ~/.local/share
getCache%LOCALAPPDATA%~/Library/Caches$XDG_CACHE_HOME or ~/.cache
getConfig%APPDATA%~/Library/Preferences$XDG_CONFIG_HOME or ~/.config