I/O Operations in Gleam
Learn console output, formatted printing, file reading and writing, and Result-based I/O error handling in Gleam with Docker-ready examples
Input and output are where a program meets the outside world. In Hello World you called io.println once; here we go further — formatting values for the console, writing to standard error, and reading and writing files.
Gleam’s take on I/O is shaped by its design. There is no printf and no format-string statement. Because the language is statically typed with no variadic formatting, you produce output by building strings explicitly — joining pieces with the <> operator and converting values with module functions like int.to_string and float.to_string. The gleam/io module, part of the standard library, handles the console: println and print for standard output, plus println_error and print_error for standard error.
Anything that touches the filesystem lives outside the core standard library, in small focused packages. File access uses simplifile, which you add to a project with gleam add simplifile. And crucially, Gleam has no exceptions: every operation that can fail — reading a missing file, parsing a number — returns a Result value that you pattern match on with case. That makes error handling part of the type system rather than an afterthought. This tutorial covers formatted console output, file reading and writing, and Result-based error handling, all runnable in Docker.
Formatted Console Output
Since Gleam has no printf, formatted output is just string building. You convert each value to a String and concatenate. Create a file named io_output.gleam:
| |
The <> operator concatenates strings, and each value is turned into text by its module: int.to_string for integers, float.to_string for floats. Note /. — Gleam uses distinct operators for float (/.) and integer (/) division, so the types never mix silently. println_error sends its output to standard error, which keeps diagnostics separate from your program’s real output.
Writing and Reading Files
File I/O comes from the simplifile package rather than the standard library. Every function returns a Result, so reading and writing are the same shape as any other fallible operation. Create a file named io_files.gleam:
| |
simplifile.write and simplifile.append use labelled arguments (to: and contents:) so the call reads like a sentence, and both hand you back a Result(Nil, FileError) — here we discard it with let _ =. Reading returns Result(String, FileError), which case forces you to handle. Once the text is in memory, ordinary Gleam pipelines take over: string.split breaks it into lines, list.index_map pairs each line with its index, and list.each prints them.
Handling I/O Errors with Result
Because failures are values, not exceptions, you handle a missing file the same way you handle any other Result — by matching its Error case. Create a file named io_errors.gleam:
| |
The second read fails, but the program does not crash. The Error branch receives a FileError value describing what went wrong, and simplifile.describe_error turns it into a human-readable message (for a missing file, "No such file or directory."). This is the heart of Gleam’s error story: there is no try/catch, no stack unwinding, and no way to forget a failure case — the compiler will not let a case on a Result compile unless you handle both Ok and Error.
Reading Interactive Input
Reading a line typed at a terminal is deliberately not part of Gleam’s standard library, and it is uncommon in BEAM programs, which more often receive input over the network or from files. When you do need it, a dedicated package such as stdin provides it (gleam add stdin), returning the same Result-shaped values you have seen above. For batch programs, reading from a file — as shown in the previous sections — is the usual way Gleam takes input, and it keeps the examples fully reproducible.
Running with Docker
Like Hello World, each example is copied into a fresh Gleam project and run. The file examples also run gleam add simplifile to pull in the file-I/O package:
| |
Each command creates a project called hello, copies your source into src/hello.gleam (the module gleam run executes), and compiles and runs it.
Expected Output
Running io_output.gleam (the println_error line goes to standard error, so it is not part of the standard output shown here):
Standard output, one line at a time.
No newline here... continued on the same line.
Name: Ada, Age: 36
Pi is approximately 3.14159
Half of 3 is 1.5
====================
DONE
Running io_files.gleam:
--- notes.txt ---
First line
Second line
Appended line
--- languages.txt ---
0: Gleam
1: Erlang
2: Elixir
Running io_errors.gleam:
Read present.txt: hello
Could not read missing.txt: No such file or directory.
Key Concepts
- No
printf— build strings — Gleam produces formatted output by concatenating with<>and converting values explicitly (int.to_string,float.to_string), so every value’s type is checked as you assemble the line. printvsprintln—io.printwrites without a trailing newline whileio.printlnadds one; both have_errorvariants (print_error,println_error) that write to standard error.- Separate numeric operators —
/.divides floats and/divides integers; the types never mix silently, which is why float and int conversions come from different modules. - File I/O is a package —
simplifile(added withgleam add simplifile) providesread,write, andappend, using labelled arguments (from:,to:,contents:) that make calls read naturally. - Failures are values, not exceptions — every fallible I/O call returns a
Result; there is notry/catch, and the compiler refuses to build acaseon aResultunless bothOkandErrorare handled. describe_errorfor messages —simplifile.describe_errorturns aFileErrorinto a readable string, so you can report why an operation failed without pattern matching on every variant.- Pipelines around I/O — the effect itself is a single call, but the data around it stays functional:
string.split,list.index_map, andlist.eachprocess file contents in a readable top-to-bottom flow.
Running Today
All examples can be run using Docker:
docker pull ghcr.io/gleam-lang/gleam:v1.14.0-erlang-alpine
Comments
Loading comments...
Leave a Comment