String
String — UTF-8 text operations.
Strings in Beamtalk are UTF-8 encoded binaries (Erlang binaries). All string operations are grapheme-aware.
BEAM Mapping
Beamtalk strings map directly to Erlang binaries.
Examples
"hello" class // => String
"hello" length // => 5
"hello" ++ " world" // => "hello world"
Methods
- class » withAll: list
- class » fromCodePoint: codePoint
- class » fromCodePoints: list
- class » fromIolist: iolist
- =:= other
- =/= other
- /= other
- < other
- > other
- <= other
- >= other
- ++ other
- , other
- length
- size
- at: index
- first
- last
- uppercase
- lowercase
- capitalize
- trim
- trimLeft
- trimRight
- reverse
- includesSubstring: substring
- startsWith: prefix
- endsWith: suffix
- indexOf: substring
- split: separator
- splitOn: pattern
- repeat: n
- lines
- words
- replaceAll: old with: new
- replaceFirst: old with: new
- take: n
- drop: n
- padLeft: width
- padRight: width
- padLeft: width with: char
- padRight: width with: char
- isEmpty
- isNotEmpty
- isBlank
- isDigit
- isAlpha
- asInteger
- asFloat
- asAtom
- asList
- do: block
- collect: block
- select: block
- reject: block
- stream
- matchesRegex: pattern
- matchesRegex: pattern options: opts
- firstMatch: pattern
- allMatches: pattern
- replaceRegex: pattern with: replacement
- replaceAllRegex: pattern with: replacement
- splitRegex: pattern
- printString
- asString
- displayString
- urlEncoded
- urlDecoded
Class Methods
Create a String by joining a list of grapheme cluster strings.
Useful for constructing a String from the result of asList or
select: operations. Each element should be a grapheme string.
Examples
String class withAll: #("h", "e", "l", "l", "o") // => "hello"
Create a single-character String from a Unicode code point integer.
Examples
String fromCodePoint: 65 // => "A"
String fromCodePoint: 8364 // => "€"
Create a String from a list of Unicode code point integers.
Examples
String fromCodePoints: #(72, 105) // => "Hi"
String fromCodePoints: #(123, 125) // => "\{\}"
Convert an Erlang iolist or charlist to a String binary.
Useful for coercing the result of Erlang FFI calls that return iolists (nested lists of binaries and integers) into a plain String.
Examples
String fromIolist: #(104, 105) // => "hi"
Instance Methods
Test strict equality with another string.
Examples
"abc" =:= "abc" // => true
"abc" =:= "xyz" // => false
Test strict inequality with another string.
Examples
"abc" =/= "xyz" // => true
"abc" =/= "abc" // => false
Test inequality with another string.
Examples
"abc" /= "xyz" // => true
"abc" /= "abc" // => false
Test if the receiver sorts before another string.
Examples
"abc" < "xyz" // => true
"xyz" < "abc" // => false
Test if the receiver sorts after another string.
Examples
"xyz" > "abc" // => true
"abc" > "xyz" // => false
Test if the receiver sorts before or equal to another string.
Examples
"abc" <= "xyz" // => true
"abc" <= "abc" // => true
Test if the receiver sorts after or equal to another string.
Examples
"xyz" >= "abc" // => true
"abc" >= "abc" // => true
Concatenate the receiver with another string.
Examples
"hello" ++ " world" // => "hello world"
"a" ++ "b" // => "ab"
Concatenate the receiver with another string (Smalltalk-style comma operator).
Equivalent to ++. Provided for Smalltalk compatibility.
Examples
"foo" , "bar" // => "foobar"
"hello" , " world" // => "hello world"
Number of grapheme clusters in the string.
Examples
"hello" length // => 5
"" length // => 0
Alias for length.
Examples
"hello" size // => 5
Return the grapheme cluster at the given 1-based index.
Raises index_out_of_bounds if index is outside 1..self length, and
empty_collection if the String is empty.
Examples
"hello" at: 1 // => "h"
"hello" at: 5 // => "o"
Return the first grapheme cluster.
Raises empty_collection if the String is empty — there is no character
to answer. Guard with isEmpty, or use take: 1, which answers "".
Examples
"hello" first // => "h"
"über" first // => "ü"
Return the last grapheme cluster.
Raises empty_collection if the String is empty — there is no character
to answer. Guard with isEmpty before calling.
Examples
"hello" last // => "o"
Convert all characters to uppercase.
Examples
"hello" uppercase // => "HELLO"
Convert all characters to lowercase.
Examples
"HELLO" lowercase // => "hello"
Capitalize the first character.
Examples
"hello" capitalize // => "Hello"
Remove leading and trailing whitespace.
Examples
" hello " trim // => "hello"
Remove leading whitespace.
Examples
" hello" trimLeft // => "hello"
Remove trailing whitespace.
Examples
"hello " trimRight // => "hello"
Reverse the string (grapheme-aware).
Examples
"hello" reverse // => "olleh"
Test if the receiver contains a substring.
Examples
"hello world" includesSubstring: "world" // => true
"hello" includesSubstring: "xyz" // => false
Test if the receiver starts with the given prefix.
Examples
"hello" startsWith: "hel" // => true
"hello" startsWith: "xyz" // => false
Test if the receiver ends with the given suffix.
Examples
"hello" endsWith: "llo" // => true
"hello" endsWith: "xyz" // => false
Return the 1-based index of the first occurrence of a substring, or nil if not found.
Examples
"hello" indexOf: "ell" // => 2
"hello" indexOf: "xyz" // => nil
Split the string by a separator.
Examples
"a,b,c" split: "," // => #("a", "b", "c")
Split the string by a pattern.
Examples
"a::b::c" splitOn: "::" // => #("a", "b", "c")
Repeat the string n times.
Examples
"ab" repeat: 3 // => "ababab"
Split the string into lines.
Examples
"a\nb\nc" lines // => #("a", "b", "c")
Split the string into words (whitespace-separated).
Examples
"hello world" words // => #("hello", "world")
Replace all occurrences of old with new.
Examples
"aabaa" replaceAll: "a" with: "x" // => "xxbxx"
Replace the first occurrence of old with new.
Examples
"aabaa" replaceFirst: "a" with: "x" // => "xabaa"
Take the first n grapheme clusters.
Examples
"hello" take: 3 // => "hel"
Drop the first n grapheme clusters.
Examples
"hello" drop: 2 // => "llo"
Left-pad the string to the given width with spaces.
Examples
"hi" padLeft: 5 // => " hi"
Right-pad the string to the given width with spaces.
Examples
"hi" padRight: 5 // => "hi "
Left-pad the string to the given width with the specified character.
Examples
"hi" padLeft: 5 with: "0" // => "000hi"
Right-pad the string to the given width with the specified character.
Examples
"hi" padRight: 5 with: "0" // => "hi000"
Test if the string is empty.
Examples
"" isEmpty // => true
"hello" isEmpty // => false
Test if the string is not empty.
Examples
"hello" isNotEmpty // => true
"" isNotEmpty // => false
Test if the string is empty or contains only whitespace.
Examples
" " isBlank // => true
"" isBlank // => true
Test if all characters are digits.
Examples
"123" isDigit // => true
"12a" isDigit // => false
Test if all characters are letters.
Examples
"abc" isAlpha // => true
"ab1" isAlpha // => false
Parse the string as an integer.
Examples
"42" asInteger // => 42
Parse the string as a float.
Examples
"3.14" asFloat // => 3.14
Convert the string to an atom (Symbol).
Examples
"hello" asAtom // => #hello
Convert the string to a list of grapheme cluster strings.
Examples
"abc" asList // => #("a", "b", "c")
Iterate over each grapheme cluster, evaluating block with each one.
Examples
"abc" do: [:c | Transcript show: c]
Collect results of evaluating block on each grapheme cluster.
Returns a String built by concatenating the block results.
Examples
"abc" collect: [:c | c uppercase] // => "ABC"
Select grapheme clusters for which block returns true.
Returns a String of the matching grapheme clusters (filtered graphemes remain valid graphemes).
Examples
"a1b2" select: [:c | c isAlpha] // => "ab"
Reject grapheme clusters for which block returns true.
Returns a String of the grapheme clusters that were not rejected.
Examples
"a1b2" reject: [:c | c isAlpha] // => "12"
Return a lazy Stream over the characters (grapheme clusters).
Examples
("hello" stream) take: 3 // => #("h", "e", "l")
Test if the string matches a regular expression pattern. Accepts a String pattern or compiled Regex object.
Examples
"hello123" matchesRegex: "[0-9]+" // => true
"hello" matchesRegex: "^[0-9]+$" // => false
Test if the string matches a pattern with PCRE options.
Examples
"Hello" matchesRegex: "[a-z]+" options: #(#caseless) // => true
Find the first regex match, returning matched String or nil.
Examples
"hello123world" firstMatch: "[0-9]+" // => "123"
"hello" firstMatch: "[0-9]+" // => nil
Find all regex matches, returning a List of Strings.
Examples
"a1b2c3" allMatches: "[0-9]+" // => #("1", "2", "3")
Replace the first regex match with a replacement string.
Examples
"hello world" replaceRegex: "[aeiou]" with: "*" // => "h*llo world"
Replace all regex matches with a replacement string.
Examples
"hello world" replaceAllRegex: "[aeiou]" with: "*" // => "h*ll* w*rld"
Split the string by a regex pattern.
Examples
"a,,b,,,c" splitRegex: ",+" // => #("a", "b", "c")
Return a developer-readable string representation (with surrounding quotes). Embedded double-quote characters are doubled (Beamtalk string literal convention).
Examples
"hello" printString // => """hello"""
Return the string itself (identity conversion).
Examples
"hello" asString // => "hello"
Return the string itself for user-facing display (no surrounding quotes).
Examples
"hello" displayString // => "hello"
Percent-encode characters outside the URL-safe unreserved set
(RFC 3986 §2.3: letters, digits, -, ., _, ~).
Encodes every reserved/special character, including /, +, and
space — use this for a value that will be placed inside a single URL
path segment or query component, not for a value that already is a
full URL.
Examples
"hello world" urlEncoded // => "hello%20world"
"a/b+c" urlEncoded // => "a%2Fb%2Bc"
The underlying FFI spec types the result binary() (String | Binary),
but beamtalk_string:urlEncoded/1 always builds an ASCII string —
suppress the resulting String | Binary vs. declared String
return-type mismatch.
Decode a percent-encoded string.
Inverse of urlEncoded. Any %XX escape is decoded to its byte;
characters with no escape pass through unchanged. Raises a
parse_error when a % is followed by two characters that aren't
both valid hex digits (e.g. %ZZ); a truncated escape at the end of
the string (%2, or a bare trailing %) is left unchanged rather
than rejected.
Examples
"hello%20world" urlDecoded // => "hello world"
"a%2Fb%2Bc" urlDecoded // => "a/b+c"
Inherited Methods
From Binary
Return the byte count of this binary.
Examples
(Binary serialize: 42) size // => _
Iterate over each byte (Integer 0-255), evaluating block with each one.
Examples
(Binary fromBytes: #(104, 101)) do: [:b | Transcript show: b]
Return a developer-readable string representation.
Displays hex representation for non-UTF-8 binaries, or quoted string for valid UTF-8 binaries.
Examples
(Binary fromBytes: #(104, 101)) printString // => _
Return the byte value (0-255) at the given 1-based index.
Raises index_out_of_bounds if the index is out of range.
Examples
(Binary fromBytes: #(104, 101, 108)) at: 1 // => 104
Return the byte value (0-255) at the given 0-based offset.
Uses 0-based indexing to match Erlang's binary:at/2.
Raises index_out_of_bounds if the offset is out of range.
Examples
(Binary fromBytes: #(104, 101, 108)) byteAt: 0 // => 104
Return the byte count of this binary.
Alias for size on Binary. On String, provides unambiguous byte count
(since String overrides size with grapheme count).
Examples
(Binary fromBytes: #(104, 101, 108)) byteSize // => 3
Return a zero-copy slice of this binary.
Takes a 0-based offset and length. Raises index_out_of_bounds
if the range is invalid.
Examples
(Binary fromBytes: #(1, 2, 3, 4, 5)) part: 1 size: 3 // => _
Concatenate this binary with another binary.
Examples
(Binary fromBytes: #(1, 2)) concat: (Binary fromBytes: #(3, 4)) // => _
Convert this binary to a list of byte integers (0-255).
Examples
(Binary fromBytes: #(104, 101)) toBytes // => #(104, 101)
Validate UTF-8 and return the binary as a String.
Returns a Result: success gives a String, failure gives an error with the byte offset of the invalid sequence.
Examples
(Binary fromBytes: #(104, 101, 108, 108, 111)) asString // => _
Return this binary as a String without UTF-8 validation.
Use when you trust the source data is valid UTF-8.
Examples
(Binary fromBytes: #(104, 101, 108, 108, 111)) asStringUnchecked // => "hello"
Encode as a standard (RFC 4648 §4) base64 string, with = padding.
Examples
(Binary fromBytes: #(104, 101, 108, 108, 111)) asBase64 // => "aGVsbG8="
The underlying FFI spec types the result binary() (String | Binary),
but beamtalk_binary:'asBase64:'/1 always builds an ASCII base64
string — suppress the resulting String | Binary vs. declared String
return-type mismatch.
Encode as a URL-safe (RFC 4648 §5) base64 string, with = padding.
Uses -/_ in place of +// so the result is safe to embed
directly in a URL path or query component without further escaping.
Examples
(Binary fromBytes: #(251, 239)) asBase64 // => "++8="
(Binary fromBytes: #(251, 239)) asBase64Url // => "--8="
Encode as a lowercase hexadecimal string.
Examples
(Binary fromBytes: #(104, 101, 108, 108, 111)) asHex // => "68656c6c6f"
From Collection
Return the number of elements.
Iterate over each element, evaluating block with each one.
Return a developer-readable string representation.
Return the class used to build results from collection operations.
Used by collect:, select:, and reject: to return the same
collection type as the receiver. Sealed subclasses override this.
Examples
#(1, 2) species // => List
#[1, 2] species // => Array
Test if the collection has no elements.
Examples
#() isEmpty // => true
#(1) isEmpty // => false
Test if the collection has at least one element.
Examples
#(1) isNotEmpty // => true
#() isNotEmpty // => false
Return any single element of the collection — no ordering guarantee.
Intended for the unordered collections (Set, Bag, Dictionary),
which deliberately have no first/last: there is no canonical order
to answer from, so this answers some element without promising
which one — the answer may differ between calls, and callers must not
rely on it being stable. Ordered collections (Array, Interval,
List) inherit it too, but should reach for first/last instead
when order matters.
Defined once here, not per-subclass: do: already gives every
collection a way to grab one element — whichever one do: reaches
first, in the receiver's own iteration order. Raises
empty_collection if the collection has no elements.
Uses ^ (non-local return) for early exit — compiles to throw/catch
on BEAM, the same trick detect:/anySatisfy: use further below.
Examples
(Set new add: 1) anyOne // => 1
((Bag new add: 1) anyOne) // => 1
(#{#a => 1} anyOne) // => 1
Test if the collection contains the given element.
Default implementation iterates with do: and returns early on match.
Subclasses may override with more efficient lookup.
Compares with equals:, so an element class that overrides it is matched
by value rather than by representation (BT-2997). Set overrides this
with a sorted-list lookup and so compares with raw =:= instead — keyed
containers decide identity in the VM and cannot honour equals:.
Goes through beamtalk_equality:eq/2 rather than sending equals:
directly. A bare send would reach Object>>equals: on an actor
element as a blocking gen_server:call — turning this scan into an RPC
per element that can raise deadlock_detected or time out. eq/2 tries
raw =:= first and only dispatches to tagged value types, so actors
answer by identity, as they must.
Examples
#(1, 2, 3) includes: 2 // => true
#(1, 2, 3) includes: 9 // => false
Reduce the collection with an accumulator.
Evaluates block with (accumulator, element) for each element.
Returns the final accumulator value.
Kept as @primitive because the pure-BT implementation using do: with
local-variable mutation does not work for abstract-class methods: the
compiler generates lists:foreach (no state threading) instead of
lists:foldl. The Erlang helper calls the block as Block(Acc, Elem)
(accumulator first) to match the Beamtalk block value: acc value: each
convention expected by collect:, select:, and reject:.
Examples
#(1, 2, 3) inject: 0 into: [:sum :x | sum + x] // => 6
Collect results of evaluating block on each element.
Returns a collection of the same type as the receiver (species pattern).
Builds the result in reverse using addFirst: then converts via species withAll:.
Examples
#(1, 2, 3) collect: [:x | x * 2] // => #(2, 4, 6)
Like collect:, but evaluates block for every element concurrently
(one spawned process per element, via Parallel all: — BT-2974)
instead of sequentially.
Concurrency is unbounded — one process is spawned per element, with
no pooling or throttling. Use parallelCollect:maxConcurrency: for
very large collections where that matters.
If any element's block evaluation fails, parallelCollect: re-raises
that failure (the first one, in element order) — matching collect:'s
own behaviour of propagating an exception raised by block. Use
Parallel all: directly (on self collect: [:each | [block value: each]]) if you need every per-element Result, including partial
failures, instead of a raise.
Examples
#(1, 2, 3) parallelCollect: [:x | x * 2] // => #(2, 4, 6)
Like parallelCollect:, but bounds concurrency to maxConcurrency
processes at a time instead of spawning one per element.
The receiver is split into consecutive chunks of at most
maxConcurrency elements; each chunk runs concurrently (via Parallel all:), and the next chunk only starts once every element of the
current one has finished. This is chunked bounded concurrency, not a
streaming worker pool — a chunk's slowest element gates the next
chunk's start, so a pool where finished slots immediately pick up new
work would use fewer total processes over time for uneven workloads.
Chunking is simple, correct, and enough to cap resource usage for very
large collections; reach for Parallel all: directly with your own
work-stealing queue if you need true streaming concurrency.
Raises #type_error if maxConcurrency is not a positive Integer.
Failure behaviour matches parallelCollect:: the first failure (in
element order within the failing chunk) is re-raised.
Examples
#(1, 2, 3, 4, 5) parallelCollect: [:x | x * 2] maxConcurrency: 2
// => #(2, 4, 6, 8, 10)
Runs blocks in consecutive Parallel all: chunks of at most
maxConcurrency elements, preserving overall order.
Tail-recursive helper for runChunked:maxConcurrency: — acc builds
up in reverse (each chunk's results prepended via addFirst:, one at a
time, so the recursive step stays a genuine BEAM tail call regardless
of how many chunks there are) and is reversed once at the end.
Select elements for which block returns true.
Returns a collection of the same type as the receiver (species pattern).
Builds the result in reverse using addFirst: then converts via species withAll:.
Examples
#(1, 2, 3, 4) select: [:x | x > 2] // => #(3, 4)
Reject elements for which block returns true.
Examples
#(1, 2, 3, 4) reject: [:x | x > 2] // => #(1, 2)
Find the first element for which block returns true.
Raises not_found if no element matches — the return type is E, so
there is no in-band way to say "nothing matched". Every collection
agrees on this: Set, Bag, Dictionary, Interval, and Binary /
String inherit this implementation, and the native overrides on List
and Stream raise the same kind. detect:ifNone: is the non-raising
alternative on all of them.
The error names the receiver's class rather than Collection, so a
no-match on a Set reports Set.
Uses ^ (non-local return) for early exit — this compiles to
throw/catch on BEAM.
Examples
#(1, 2, 3) detect: [:x | x > 1] // => 2
Find the first element matching block, or evaluate noneBlock if none.
Uses ^ (non-local return) for early exit — compiles to throw/catch on BEAM.
noneBlock is deliberately Block(Object), not Block(E): the fallback
commonly produces a value outside the element type (ifNone: [nil],
ifNone: [#missing]), so narrowing it to E would reject those
legitimate uses. The trade-off — a wrong-typed default is not flagged —
is intentional, and is why the return type is E | Object.
Examples
#(1, 2) detect: [:x | x > 5] ifNone: [0] // => 0
Test if any element satisfies block.
Uses ^ (non-local return) for early exit — compiles to throw/catch on BEAM.
Examples
#(1, 2, 3) anySatisfy: [:x | x > 2] // => true
Test if all elements satisfy block.
Uses ^ (non-local return) for early exit — compiles to throw/catch on BEAM.
Examples
#(2, 4, 6) allSatisfy: [:x | x isEven] // => true
Test if no element satisfies block.
Examples
#(1, 2, 3) noneSatisfy: [:x | x > 5] // => true
#(1, 2, 3) noneSatisfy: [:x | x > 2] // => false
Count the elements for which block returns true.
Examples
#(1, 2, 3, 4) count: [:x | x > 2] // => 2
#() count: [:x | x > 2] // => 0
Sum all elements. Returns 0 for an empty collection.
Uses native numeric addition (intended for Integer/Float); it does
not dispatch a Beamtalk + message. Kept as @primitive because the
pure-BT fold performs arithmetic on the generic element type E, which
the gradual type checker cannot prove is numeric.
Examples
#(1, 2, 3) sum // => 6
#() sum // => 0
Return the largest element.
Compares using the runtime's native total ordering (intended for
Integer/Float) — it does not dispatch a Beamtalk > message, so a
custom > method on the element type is not honoured. Raises a
#beamtalk_error on an empty collection — there is no maximum of nothing.
Examples
#(3, 1, 4, 1, 5) max // => 5
Return the smallest element.
Compares using the runtime's native total ordering (intended for
Integer/Float) — it does not dispatch a Beamtalk < message. Raises
a #beamtalk_error on an empty collection.
Examples
#(3, 1, 4, 1, 5) min // => 1
Return the mean of the elements as a Float.
Uses native numeric addition (intended for Integer/Float). Raises a
#beamtalk_error on an empty collection.
Examples
#(1, 2, 3, 4) average // => 2.5
Iterate over each element with its 1-based index.
Evaluates block with (element, index) for each element.
Examples
#("a", "b") eachWithIndex: [:item :i | Transcript show: i]
Iterate over each element, evaluating separatorBlock between elements.
The separator runs between consecutive elements, not before the first or after the last. Useful for joining/formatting.
Examples
#(1, 2, 3) do: [:x | Transcript show: x] separatedBy: [Transcript show: ", "]
Convert to a List, in iteration order.
List is the canonical eager sequence. Note: for a Dictionary this
yields its values (consistent with do:); for a Bag, each element is
repeated by its occurrence count.
Examples
(1 to: 3) asList // => #(1, 2, 3)
(Set withAll: #(1, 2, 3)) asList sort // => #(1, 2, 3)
Convert to an Array.
Examples
(1 to: 3) asArray // => #[1, 2, 3]
Convert to a Set, discarding duplicates.
Examples
#(1, 2, 2, 3) asSet size // => 3
Convert to a Bag, counting occurrences.
Examples
(#(1, 1, 2) asBag) occurrencesOf: 1 // => 2
Return a string representation.
From Value
Return a developer-readable string representation showing fields.
Produces ClassName(field: value, ...) via the canonical structural
renderer (ADR 0094). Field values are rendered with their own
printString (strings stay quoted, nested values show their structural
form), in sorted field order. A class with no fields produces
ClassName(). Recursion is bounded by depth/width/length caps with a
cycle guard.
Examples
ValuePoint x: 3 y: 4 printString // => "ValuePoint(x: 3, y: 4)"
ValuePoint new printString // => "ValuePoint(x: 0, y: 0)"
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