File I/O
Luma treats files as values that reference paths, not as open handles.
Creating a file value never opens the file or touches the filesystem.
All file operations are explicit, atomic, and predictable.
Creating a file reference
f: file = file("data.txt")This creates a reference to a path.
No file is opened, created, or validated at this point.
You can safely create references to files that do not exist yet.
Reading files
Luma uses type-based dispatch for reading files.
The same method (read()) adapts its behavior based on the declared result type.
Read entire file as text
content: str = file("config.txt").read()- Reads the entire file as a string
- Panics if the file does not exist
Use this when the file is required.
Read entire file as optional text
content: ?str = file("config.txt").read()
if content != nil {
print(content)
}- Returns
nilif the file does not exist - Never panics
Use this for optional configuration or cache files.
Read file as lines
lines: [str] = file("data.txt").read()
lines.walk(i, line) -> {
print(line)
}- Splits on line breaks
- Handles both Unix and Windows line endings
- Panics if the file does not exist
Use this for logs, CSV files, and line-oriented data.
Read file as optional lines
lines: ?[str] = file("data.txt").read()
if lines != nil {
print(lines.len())
}- Returns
nilif the file does not exist
Read file as bytes
data: [byte] = file("image.png").read()
print(data.len())- Reads raw binary data
- Panics if the file does not exist
Use this for binary formats, media files, or protocol data.
Read file as optional bytes
data: ?[byte] = file("image.png").read()
if data != nil {
// process bytes
}Writing files
Write text (replace content)
file("output.txt").write("Hello, world")- Creates the file if it does not exist
- Replaces existing content if it does
Write bytes (replace content)
data: [byte] = [0x48, 0x65, 0x6C, 0x6C, 0x6F]
file("output.bin").write(data)Use this for binary output.
Add a line (append with newline)
log: file = file("app.log")
log.add("Application started")
log.add("User logged in")- Appends text
- Automatically adds a newline
- Creates the file if it does not exist
This is the recommended way to write logs.
Append raw data (no newline)
log.append("[CONTINUED] ")
log.add("Recovered after restart")Use this only when you explicitly want to control formatting.
File information
Check existence
if file("data.txt").exists() {
print("File exists")
}Get file size
size: int = file("large.dat").size()Returns size in bytes.
Panics if the file does not exist.
Get file name
name: str = file("docs/report.txt").name() // "report.txt"Get file extension
ext: str = file("image.png").ext() // ".png"Returns an empty string if there is no extension.
Get full path
path: str = file("data/file.txt").path()Returns the path exactly as provided to file().
Get directory path
dir: str = file("docs/report.txt").dir() // "docs"File actions
Create file
file("new.txt").create()- Creates an empty file
- Safe to call even if the file already exists
Delete file
file("temp.txt").delete()Panics if the file does not exist.
Copy file
file("document.txt").copy("backup/document.txt")- Creates destination if needed
- Overwrites destination if it exists
Move (rename) file
file("old.txt").move("new.txt")Note: after moving, the original file reference still points to the old path.
Pattern matching with glob
files: [file] = glob("logs/*.log")Supported patterns include:
*– any sequence of characters?– any single character[abc]– character classes[a-z]– character ranges**– recursive directory matching
Examples
glob("*.txt")
glob("logs/*.log")
glob("**/*.luma")
glob("data[0-9].txt")If no files match, an empty list is returned.
Common patterns
Safe configuration loading
fn load_config(path: str) -> str {
config: ?str = file(path).read()
if config != nil {
return config
}
return "default=value"
}Process multiple files
files: [file] = glob("data/*.txt")
files.walk(i, f) -> {
print(f.name())
}Ensure file exists
f: file = file("settings.txt")
if !f.exists() {
f.create()
f.write("default settings")
}Planned features
The following methods are planned but not yet implemented:
created() -> date // file creation time
updated() -> date // last modification timeThese will become available once Luma introduces a date type.
Design notes
- Files are path references, not open handles
- All operations are atomic (open → operate → close)
- Error handling uses optional types instead of exceptions
- No explicit open/close or streaming APIs are required
- The common case remains simple, while rare cases stay possible