File
File — File system operations.
Provides file I/O operations and lazy file streaming using Erlang's
file module. All operations are class methods. Errors use structured
#beamtalk_error{} records.
Examples
File exists: "test.txt"
File readAll: "test.txt"
File writeAll: "output.txt" contents: "hello"
File readBinary: "image.png"
File writeBinary: "output.bin" contents: data
File appendBinary: "log.bin" contents: data
(File lines: "data.csv") do: [:line | Transcript show: line]
File open: "data.csv" do: [:handle | handle lines take: 10]
File open: "events.log" mode: #append do: [:h | h writeLine: "e". h sync]
@see System (for environment variables and OS information) @see Json (for reading/writing JSON files)
Methods
- class » exists: path
- class » readAll: path
- class » writeAll: path contents: text
- class » readBinary: path
- class » writeBinary: path contents: binary
- class » appendBinary: path contents: binary
- class » lines: path
- class » open: path do: block
- class » open: path mode: mode
- class » open: path mode: mode do: block
- class » lastModified: path
- class » isDirectory: path
- class » isFile: path
- class » mkdir: path
- class » mkdirAll: path
- class » listDirectory: path
- class » delete: path
- class » deleteAll: path
- class » rename: from to: to
- class » absolutePath: path
- class » cwd
- class » tempDirectory
- class » openHandles
Class Methods
Test if a file exists at the given path (class method).
Examples
File exists: "test.txt" // => true or false
Read the entire contents of a file as a string (class method).
Returns Result ok: contents on success, or Result error: err on failure.
Examples
File readAll: "test.txt" // => Result ok: "file contents..."
Write text to a file, creating or overwriting it (class method).
Returns Result ok: nil on success, or Result error: err on failure.
Examples
File writeAll: "output.txt" contents: "hello"
Read the entire contents of a file as raw binary (class method).
Returns Result ok: binary on success, or Result error: err on failure.
Unlike readAll:, this does not assume the contents are a UTF-8 string.
Examples
File readBinary: "image.png" // => Result ok: <<...>>
Write binary data to a file, creating or overwriting it (class method).
Returns Result ok: nil on success, or Result error: err on failure.
Examples
File writeBinary: "output.bin" contents: data
Append binary data to a file, creating it if needed (class method).
Returns Result ok: nil on success, or Result error: err on failure.
Examples
File appendBinary: "log.bin" contents: data
Return a lazy Stream of lines from a file (class method).
Opens the file and returns Result ok: stream on success, or
Result error: err on failure. The Stream reads one line at a time
and closes the handle automatically when exhausted. Constant memory —
safe for large files.
Cross-process constraint: file-backed Streams must be consumed by the same process that created them.
Examples
(File lines: "data.csv") unwrap take: 5
(File lines: "log.txt") unwrap select: [:l | l includesSubstring: "ERROR"]
Block-scoped file handle with automatic cleanup (class method).
Opens the file, passes a FileHandle to the block, and ensures
the handle is closed when the block exits (normally or via exception).
Returns Result ok: blockResult on success, or Result error: err
on failure.
The handle responds to lines which returns a Stream of lines.
Both the handle and any Streams derived from it must be consumed
within the block — they must not escape, as the file descriptor
is closed when the block returns.
The block runs in your own process (ADR 0109), so it may call File
again.
Examples
(File open: "data.csv" do: [:handle |
handle lines take: 10
]) unwrap
Open a file in the given mode and return a FileHandle (class method).
Modes:
| Mode | Behaviour |
|---|---|
#read | Read only; the file must exist |
#write | Truncate or create, write only |
#append | Create if absent; every write goes to the end |
#readWrite | Create if absent; existing contents kept |
Write-capable modes create missing parent directories. Returns
Result ok: handle, or Result error: err.
The caller owns the handle and must close it, but is not the only
backstop: it is registered against the REPL session if there is one,
else the calling actor, else left unowned, and closed automatically
when that owner dies. File openHandles lists every outstanding
handle for diagnostics. Prefer open:mode:do: whenever a block scope
will do — it needs no owner at all.
Examples
handle := (File open: "events.log" mode: #append) unwrap
handle writeLine: "started".
handle sync.
handle close.
Block-scoped handle in the given mode, closed however the block exits (class method).
Opens the file, passes the FileHandle to the block, and guarantees the
handle is closed on the way out — normal return, raised error, or
non-local return alike. Returns Result ok: blockResult on success, or
Result error: err if the file could not be opened.
The handle must not escape the block; the descriptor is closed when the
block returns. See open:mode: for the mode Symbols.
The block runs in your own process (ADR 0109), so it may call File
again, holds nothing else up, and is under no time limit.
Examples
(File open: "events.log" mode: #append do: [:handle |
handle writeLine: "an event".
handle sync
]) unwrap
Get the last modification time of a file (class method).
Returns Result ok: DateTime on success, or Result error: err if the
file does not exist.
Examples
File lastModified: "test.txt" // => Result ok: a DateTime(...)
Test if a path refers to a directory (class method).
Examples
File isDirectory: "target" // => true or false
Test if a path refers to a regular file (class method).
Examples
File isFile: "test.txt" // => true or false
Create a directory (class method). Error if the parent does not exist.
Returns Result ok: nil on success, or Result error: err on failure.
Examples
File mkdir: "target/mydir"
Create a directory and all missing parent directories (class method).
Returns Result ok: nil on success, or Result error: err on failure.
Examples
File mkdirAll: "target/a/b/c"
List entries in a directory as a List of Strings (class method).
Returns Result ok: list on success, or Result error: err on failure.
Examples
File listDirectory: "target"
Delete a file or empty directory (class method).
Returns Result ok: nil on success, or Result error: err on failure.
Examples
File delete: "target/old.txt"
Recursively delete a directory tree (class method).
Returns Result ok: nil on success, or Result error: err on failure.
Examples
File deleteAll: "target/old-workspace"
Rename or move a file or directory (class method).
Returns Result ok: nil on success, or Result error: err on failure.
Examples
File rename: "old.txt" to: "new.txt"
Resolve a relative path to its absolute path (class method).
Returns Result ok: absPath on success, or Result error: err on failure.
Examples
File absolutePath: "target/test.txt"
Return the current working directory (class method).
Examples
File cwd // => "/home/user/projects/myapp"
Return the OS temporary directory path (class method).
Examples
File tempDirectory
List every outstanding open:mode: handle for diagnostics (class method).
Returns an Array of 3-element Arrays #(path mode owner). owner is the
REPL session or actor pid that opened the handle, or nil if it was
opened from compiled code with neither. Handles from open:do: and
open:mode:do: never appear — they are block-scoped and always closed
before the call returns.
Examples
h := (File open: "events.log" mode: #append) unwrap.
File openHandles // => #(#("events.log" #append <a Pid> or nil))
h close.
Inherited Methods
From Object
Return the class of the receiver.
Examples
42 class // => Integer
"hello" class // => String
Test if the receiver is nil. Returns false for all objects except nil.
Examples
42 isNil // => false
nil isNil // => true
Test if the receiver is not nil. Returns true for all objects except nil.
Examples
42 notNil // => true
nil notNil // => false
If the receiver is nil, evaluate nilBlock. Otherwise return self.
_nilBlock is never evaluated on this Object-level definition (only
UndefinedObject's override calls it, with Block(R) -> R), so R is
unconstrained here — parameterizing it still documents the zero-arg
shape without implying this branch produces R (BT-2834).
Examples
42 ifNil: [0] // => 42
nil ifNil: [0] // => 0
If the receiver is not nil, evaluate notNilBlock with self.
Left as a bare Block deliberately (BT-2834): notNilBlock is invoked
one-arg with self and its result becomes the method's own result, so
a precise signature needs a Self-in-Block(...) type-arg form
(Block(Self, R) -> R) with no precedent elsewhere in stdlib. The type
checker doesn't consult this declared signature for ifNotNil: anyway
— it narrows the block's parameter from the receiver's own type via
infer_args_for_if_not_nil in inference.rs (BT-2046), independent of
this stdlib declaration.
Examples
42 ifNotNil: [:v | v + 1] // => 43
nil ifNotNil: [:v | v + 1] // => nil
If nil, evaluate nilBlock; otherwise evaluate notNilBlock with self.
Bare Block params here (unlike UndefinedObject's Block(R) -> R
override, BT-2824) are intentional, not an oversight: the type checker
never consults this declared signature for these two selectors — it
reads the block arguments' actual inferred return types directly
(if_nil_branch_union_ret_ty in inference.rs, BT-2047) since a bare
-> R here can't express "whatever the block returns" without a
Self-in-Block(...) type-arg form with no precedent elsewhere in
stdlib.
Examples
42 ifNil: [0] ifNotNil: [:v | v + 1] // => 43
nil ifNil: [0] ifNotNil: [:v | v + 1] // => 0
If not nil, evaluate notNilBlock with self; otherwise evaluate nilBlock.
See ifNil:ifNotNil: above — the bare Block params are intentional.
Examples
42 ifNotNil: [:v | v + 1] ifNil: [0] // => 43
nil ifNotNil: [:v | v + 1] ifNil: [0] // => 0
Return the developer-readable (Debug) string representation.
printString is the Debug protocol (ADR 0094): the self-describing,
structural form used by the REPL, logs, and by any other printString
that nests this object. It is the REPL default — evaluating an expression
shows its printString.
This default returns the bare class name (no a/an article — the
old "a ClassName" form was dropped in ADR 0094). Value overrides it
with the structural ClassName(field: value, ...) form, actors render as
Actor(ClassName, pid), supervisors as Supervisor(ClassName, pid) /
DynamicSupervisor(ClassName, pid), and primitive types (Integer, String,
List, …) override it with their own richer output. Authors rarely override
printString directly — the default is derived.
Examples
42 printString // => "42"
Return the user-facing (Display) string representation.
displayString is the Display protocol (ADR 0094): the human-facing
form. It is the hook the language pulls during string interpolation —
every {...} segment renders via the value's displayString. Developers
rarely call it directly; they override it when a value has a natural
human rendering (e.g. Money → $10.50, where printString would still
show the Debug form).
It defaults to printString, so most types need no override. String
and Symbol demonstrate the split: "hi" printString → "\"hi\""
(quoted, Debug) while "hi" displayString → "hi" (plain, Display);
likewise #foo drops its # prefix under displayString.
displayString is not part of the Printable protocol (deferred per
ADR 0094 §5).
Examples
42 displayString // => "42"
Open a navigable Inspector cursor on the receiver.
ADR 0095 Phase 3 (BT-2504). inspect is repurposed from -> String
(the ADR-0094 deferral) to the verb that produces an Inspector — a
live, immutable cursor for drilling into the object (Inspector on: self).
anObject inspect is the shorthand; Inspector on: anObject is the
explicit spelling. The cursor exposes fields/at:/path/refresh/
printString (an indented text tree) and asDictionaries (the MCP/browser
wire form); see Inspector.
This is a breaking change: code that used inspect for its old
String result must switch to printString (the structural Debug string,
ADR 0094) — a transitional lint flags inspect used directly in ++/
string position.
Examples
42 inspect kind // => #value
(Point x: 3 y: 4) inspect fields size // => 2
(Point x: 3 y: 4) printString // => "Point(x: 3, y: 4)" (the old inspect string)
Return the receiver itself. Useful for cascading side effects.
Examples
42 yourself // => 42
Return a hash value for the receiver.
Examples
42 hash
Test value equality — the overridable counterpart to =:=.
Defaults to =:= (Erlang structural term equality), so for most classes
the two agree. Unlike =:=, this is an ordinary message send, so a class
whose logical value is not its representation can override it: a
persistent structure whose shape depends on construction history, a
timestamp that should compare by instant rather than by wall-clock fields,
or a type with a normalising form. =:=, =/=, == and /= are lowered
straight to Erlang BIFs (ADR 0002) and cannot be overridden — the compiler
rejects any attempt (BT-2997).
What honours it
The linear scans: includes: on Collection, List, Array and
Dictionary (which searches values), plus List>>indexOf: and
TestCase>>assert:equals:.
Contract
An override must agree with =:= wherever =:= holds — a =:= b must
imply a equals: b. It may only make more values equal, never fewer.
The scans above rely on this: each tries raw =:= first and dispatches
only on a miss, so a fast-path hit is always a genuine equals: hit.
Caveat
Set, Dictionary keys, and List>>unique decide identity in the VM
with raw =:=, never through this method — keying and deduplication need
an order or a hash that a user-defined equals: cannot supply. A class
that overrides equals: still deduplicates by representation when used
as a key or element. Normalise the representation if that matters.
Examples
42 equals: 42 // => true
42 equals: 42.0 // => false (defaults to strict `=:=`)
"ab" equals: "ab" // => true
Test if the receiver responds to the given selector.
Examples
42 respondsTo: #abs // => true
Return the names of fields.
Examples
42 fieldNames // => #()
Return the value of the named field.
Examples
object fieldAt: #name
Set the value of the named field (returns new state).
Examples
object fieldAt: #name put: "Alice"
Send a unary message dynamically.
Examples
42 perform: #abs // => 42
Send a message dynamically with arguments.
Examples
3 perform: #max: withArguments: #(5) // => 5
Raise an error indicating this method must be overridden by a subclass.
Examples
self subclassResponsibility
Raise an error indicating this method has not yet been implemented.
Use this for work-in-progress stubs. Distinct from subclassResponsibility,
which signals an interface contract violation.
Examples
self notImplemented
Send aValue to the current transcript without a trailing newline.
Nil-safe: does nothing when no transcript is set (batch compile, tests).
Examples
42 show: "value: "
Send aValue to the current transcript followed by a newline.
Nil-safe: does nothing when no transcript is set (batch compile, tests).
Examples
42 showCr: "hello world"
Test if the receiver is an instance of aClass or any of its subclasses.
For class-object receivers, follows Smalltalk semantics: self class
is the metaclass, so the check walks the parallel metaclass hierarchy.
The parallel chain is grounded at ProtoObject class superclass == Class
(ADR 0036), so the metaclass tower merges into the instance-side
Class → Behaviour → Object → ProtoObject chain. As a result,
Integer isKindOf: Object and Integer isKindOf: Class both return true.
Examples
42 isKindOf: Integer // => true
42 isKindOf: Object // => true
#foo isKindOf: Symbol // => true
#foo isKindOf: String // => false
Integer isKindOf: Number // => false (metaclass chain, not instance chain)
Integer isKindOf: Number class // => true (Number class is in the parallel chain)
Integer isKindOf: Object // => true (grounded — Object is reachable via the metaclass tower)
Integer isKindOf: Class // => true (Integer class inherits from Class)
Raise an error with the given message.
Examples
self error: "something went wrong"
Delegate message dispatch to the backing Erlang module (ADR 0101, BT-2720).
This method is a sentinel — a plain Object has no backing Erlang module,
so calling delegate raises an Error at runtime. Stateless Objects
declared with native: have their self delegate method bodies rewritten
by the compiler's codegen phase to call the backing module directly, so the
sentinel is never reached on a native: class.
Unlike Actor's delegate (visible only to Actor subclasses), this
Object-base sentinel is visible to every class, so delegate is a
reserved selector on the Object protocol.
Examples
42 delegate // => ERROR: delegate called on a non-native Object
From ProtoObject
Test value equality (Erlang ==, non-strict — 1 == 1.0 is true).
Examples
42 == 42 // => true
"abc" == "abc" // => true
Test value inequality (negation of ==).
Examples
1 /= 2 // => true
42 /= 42 // => false
Test strict value equality (Erlang =:= — 1 =:= 1.0 is false, unlike ==).
Every object supports this at runtime (it lowers directly to Erlang's
=:= operator regardless of receiver type, ADR 0002) — declared here,
once, so it is visible in method listings/completions/respondsTo: for
every class, not just the handful (Integer, String, ...) that
separately redeclare it with a narrower, class-typed other for
documentation purposes.
Examples
1 =:= 1 // => true
1 =:= 1.0 // => false (strict — different types)
(Dictionary new) =:= #{} // => true
Test strict value inequality (negation of =:=).
Examples
1 =/= 1.0 // => true (strict — different types)
1 =/= 1 // => false
Return the class of the receiver.
Examples
42 class // => Integer
"hello" class // => String
Handle messages the receiver does not understand. Override for custom dispatch.
Examples
42 unknownMessage // => ERROR: does_not_understand
Send a message dynamically with an arguments list.
Examples
42 perform: #abs withArguments: #() // => 42
Execute a class method in the caller's process, bypassing gen_server dispatch.
The caller takes responsibility for knowing the method does not mutate class state. Useful for long-running class methods that would otherwise block the class object's gen_server.
Limitations: only resolves methods defined directly on the target class
module (does not walk the superclass chain). Class variables and self
are not available to the method (nil and #{} are passed).
Examples
MyClass performLocally: #run:ctx: withArguments: #(input, ctx)
Send a message dynamically with an arguments list and explicit timeout.
The timeout (in milliseconds or #infinity) applies to the gen_server:call
when the receiver is an actor. For value types, timeout is ignored.
Examples
actor perform: #query withArguments: #(sql) timeout: 30000