Inspector

Inherits from Object
Sealed

Inspector — a live, immutable cursor for navigating into a single object (ADR 0095).

Where the three navigators (SystemNavigation, ProcessNavigation, AnnouncementNavigation) each enumerate a system-wide collection, an Inspector is a cursor over one object that drills into it — the Beamtalk equivalent of a Pharo Inspector. Inspector on: anObject returns a cursor; fields lists its drillable InspectorField records; at: drills into one field, returning a new child cursor; parent/root/path walk the drill chain; refresh re-captures a fresh snapshot of the same subject.

Inspector on: anObject is the explicit entry point; anObject inspect is the shorthand (ADR 0095 Phase 3, BT-2504, repurposed inspect from String to Inspector). The MCP/browser surfaces render asDictionaries / asDictionary (the typed wire form); the REPL renders printString.

The cursor is immutable. Every navigation message returns a new Inspectorat: returns a child cursor (with parent set), refresh returns a cursor on a freshly-captured snapshot. Nothing mutates in place, so a UI can hold several cursors at once.

kind-polymorphic, one class. A single Inspector carries a kind tag (#value structural, #actor snapshot) rather than a subclass per kind — the same fork ADR 0092's SupervisionNode settled. v1 covers #value (pure structural traversal of a Value's field: slots, ADR 0094 sort order) and #actor (a lazy, timeout-guarded sys:get_state snapshot of an Actor's state). A wedged, dead, or non-sys actor degrades to a single InspectorField name: #status value: #unavailable — never a crash. (#collection/#foreign and value evaluate: are later phases, ADR 0095 §6–§7.)

Inspector is a sealed typed Object subclass: a live cursor handle, like the navigators. Its carried state (subject, kind, snapshot, parent, path) lives in a runtime-minted handle — not in declarable field: slots (an Object subclass has none, ADR 0067) — and is read back through the beamtalk_inspector shim. The records it returns (InspectorField) are the Values.

Examples

i := Inspector on: (Point x: 3 y: 4)
i kind            // => #value
i fields size     // => 2
(i at: #x) unwrap subject   // => 3
i path            // => #()

Class Methods

on: anObject source

Open an inspector cursor on anObject (ADR 0095 §1).

For an actor, the timeout-guarded sys:get_state snapshot is captured here, at construction; for a value the subject is taken structurally with no process contact. anObject inspect is the shorthand for Inspector on: anObject (ADR 0095 §1).

Examples

Inspector on: (Point x: 3 y: 4)   // => an Inspector
Inspector on: aCounter            // => an Inspector (#actor)

Instance Methods

subject source

The inspected object — the value itself, or, for an actor, the captured state snapshot.

Examples

(Inspector on: (Point x: 3 y: 4)) subject   // => Point(x: 3, y: 4)
kind source

The subject kind: #value (structural), #actor (snapshot), #collection (windowed elements/associations, ADR 0095 §6), or #foreign (a non-Beamtalk OTP process, ADR 0095 §3).

Examples

(Inspector on: (Point x: 3 y: 4)) kind   // => #value
(Inspector on: aCounter) kind            // => #actor
(Inspector on: #(1, 2, 3)) kind          // => #collection
fields source

The drillable fields of the inspected object, as immutable InspectorField records (ADR 0095 §2–§3, §6).

For a #value, these are its field: slots in ADR-0094 sort order. For an #actor, they are its user state slots from a lazy, timeout-guarded snapshot — or, if the actor is busy/dead/non-sys, the single diagnostic InspectorField name: #status value: #unavailable (never a crash). For a #collection, they are the current window of elements (default page size 50, ADR 0095 §6) — ordered collections render #element fields keyed by 1-based index, keyed collections (Dictionary/Bag) render #association fields keyed by the entry key; use page: for the next window. For a #foreign process, they are best-effort #processInfo data.

Examples

(Inspector on: (Point x: 3 y: 4)) fields size   // => 2
(Inspector on: ((1 to: 1000) asList)) fields size   // => 50
size source

The cheap full element count of a #collection cursor — the collection's size, not a window walk (ADR 0095 §6). For a non-collection cursor it is the number of fields (already cheap).

Examples

(Inspector on: ((1 to: 100000) asList)) size   // => 100000
(Inspector on: (Point x: 3 y: 4)) size         // => 2
sizeOfCollection source

Internal FFI seam (ADR 0101 Part 4): the cheap element count of a #collection cursor. Keeps size pure Beamtalk.

at: aName source

Drill into one field by name, returning a child Inspector cursor on that field's value (ADR 0095 §1).

Returns a Result: Result error: (beamtalk_error no_such_field) when no field has that name. The child cursor's parent is this cursor, and its path extends this one's by the drilled name.

Examples

(Inspector on: (Point x: 3 y: 4)) at: #x     // => Result ok: (an Inspector on 3)
(Inspector on: (Point x: 3 y: 4)) at: #zzz   // => Result error: no_such_field
page: aPage source

Return a new Inspector cursor on the aPage-th window of a #collection (1-based, ADR 0095 §6).

page: 1 is the first window (the elements fields shows on a fresh cursor); page: 2 is the next 50-element window, and so on. A page past the end yields a cursor whose fields is empty. The original cursor is unchanged (immutable). Sending page: to a non-collection cursor returns Result error: (beamtalk_error not_a_collection).

Examples

big := Inspector on: ((1 to: 1000) asList)
(big page: 2) unwrap fields first value   // => 51
evaluate: src source

Evaluate the Beamtalk expression src against the inspected object, with self bound to the value (ADR 0095 §1, §7).

For a #value or #collection cursor, src is compiled and evaluated with self bound to the subject — a pure compiled dispatch — returning Result ok: theValue (or Result error: if the expression fails to compile or raises). For an #actor or #foreign cursor it returns Result error: (beamtalk_error actor_eval_unsupported): actor evaluate-in-context cannot bind self to a frozen snapshot and is a deferred follow-up (ADR 0095 §7) — drill with at: instead.

Examples

i := Inspector on: (Point x: 3 y: 0)
(i evaluate: "self x + 10") unwrap   // => 13
ci := Inspector on: aCounter
(ci evaluate: "self increment") isError   // => true (actor_eval_unsupported)
parent source

The cursor this one was drilled from, or nil at the root.

Examples

child := ((Inspector on: (Point x: 3 y: 4)) at: #x) unwrap
child parent kind   // => #value
root source

The top of this drill chain — the cursor with no parent.

Examples

child := ((Inspector on: (Point x: 3 y: 4)) at: #x) unwrap
child root kind   // => #value
path source

The breadcrumb of drilled names from the root to this cursor (for UI). #() at the root.

Examples

child := ((Inspector on: (Point x: 3 y: 4)) at: #x) unwrap
child path   // => #(#x)
refresh source

A cursor on a freshly-captured snapshot of the same subject (ADR 0095 §5). The original cursor is unchanged (immutable).

refresh re-snapshots this cursor's own subject, which differs by how the cursor was reached:

  • A root #actor cursor re-issues the guarded sys:get_state, picking up state change since the previous snapshot.
  • A #value cursor (including one drilled into an actor's slot with at:) re-freezes its already-captured value — structurally identical, since per ADR 0095 §4 drilling never re-contacts the live actor (the sub-tree is a consistent point-in-time view). To see a drilled actor field move, refresh the root actor cursor and drill again.

Examples

ci := Inspector on: aCounter   // snapshot at T0
aCounter increment             // state moves on
ci refresh fields              // a fresh cursor at T1 (root actor re-fetched)
printString source

An indented text tree of the cursor and its immediate fields, one level deep (ADR 0095 §7). The REPL default.

Examples

(Inspector on: (Point x: 3 y: 4)) printString
  // => "Inspector(Point)\n  x: 3\n  y: 4"
printStringExpanded: depth source

An indented text tree of the cursor to depth levels (ADR 0095 §7). depth: 1 is the immediate fields; deeper expands drillable children.

Examples

(Inspector on: (Point x: 3 y: 4)) printStringExpanded: 1
asDictionaries source

The cross-surface wire form — one Dictionary per drillable field (ADR 0095 §7). The MCP/browser surfaces render this structure so every surface shows equivalent data.

Each dictionary carries the field's named, typed slots: #name (the navigation key to pass back to at:), #label, #value (a JSON-stable display string), #kind, and #drillable. This is the same typed-record pattern SupervisionTree asDictionaries (ADR 0092) uses. For the cursor-level envelope (kind/path/childCount/page), use asDictionary.

Examples

(Inspector on: (Point x: 3 y: 4)) asDictionaries
// => #(#{#name => #x, #label => "x", #value => "3", ...}, ...)
asDictionary source

The whole cursor as a single wire-form Dictionary (ADR 0095 §7) — the navigable-node envelope the MCP/browser surfaces render and page through.

Carries #kind (the subject kind), #path (the breadcrumb of drilled keys from the root), #childCount (the cheap full element count for a #collection, else the field count), #page (the 1-based window index), and #fields (the asDictionaries window of field records). A surface fetches the next window by re-issuing page: and re-serialising.

Examples

((1 to: 1000) asList inspect) asDictionary
// => #{#kind => #collection, #childCount => 1000, #page => 1, #fields => #(...), ...}

Inherited Methods

From Object

class

Return the class of the receiver.

Examples

42 class              // => Integer
"hello" class         // => String
isNil

Test if the receiver is nil. Returns false for all objects except nil.

Examples

42 isNil              // => false
nil isNil             // => true
notNil

Test if the receiver is not nil. Returns true for all objects except nil.

Examples

42 notNil             // => true
nil notNil            // => false
ifNil: _nilBlock

If the receiver is nil, evaluate nilBlock. Otherwise return self.

Examples

42 ifNil: [0]         // => 42
nil ifNil: [0]        // => 0
ifNotNil: notNilBlock

If the receiver is not nil, evaluate notNilBlock with self.

Examples

42 ifNotNil: [:v | v + 1]   // => 43
nil ifNotNil: [:v | v + 1]  // => nil
ifNil: _nilBlock ifNotNil: notNilBlock

If nil, evaluate nilBlock; otherwise evaluate notNilBlock with self.

Examples

42 ifNil: [0] ifNotNil: [:v | v + 1]    // => 43
nil ifNil: [0] ifNotNil: [:v | v + 1]   // => 0
ifNotNil: notNilBlock ifNil: _nilBlock

If not nil, evaluate notNilBlock with self; otherwise evaluate nilBlock.

Examples

42 ifNotNil: [:v | v + 1] ifNil: [0]    // => 43
nil ifNotNil: [:v | v + 1] ifNil: [0]   // => 0
printString

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"
displayString

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"
inspect

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)
yourself Sealed

Return the receiver itself. Useful for cascading side effects.

Examples

42 yourself            // => 42
hash

Return a hash value for the receiver.

Examples

42 hash
respondsTo: selector Sealed

Test if the receiver responds to the given selector.

Examples

42 respondsTo: #abs    // => true
fieldNames Sealed

Return the names of fields.

Examples

42 fieldNames             // => #()
fieldAt: name Sealed

Return the value of the named field.

Examples

object fieldAt: #name
fieldAt: name put: value Sealed

Set the value of the named field (returns new state).

Examples

object fieldAt: #name put: "Alice"
perform: selector Sealed

Send a unary message dynamically.

Examples

42 perform: #abs       // => 42
perform: selector withArguments: args Sealed

Send a message dynamically with arguments.

Examples

3 perform: #max: withArguments: #(5)   // => 5
subclassResponsibility

Raise an error indicating this method must be overridden by a subclass.

Examples

self subclassResponsibility
notImplemented

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
show: aValue

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: "
showCr: aValue

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"
isKindOf: aClass

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)
error: message

Raise an error with the given message.

Examples

self error: "something went wrong"
delegate Sealed

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

== other

Test value equality (Erlang ==).

Examples

42 == 42           // => true
"abc" == "abc"     // => true
/= other

Test value inequality (negation of ==).

Examples

1 /= 2             // => true
42 /= 42           // => false
class

Return the class of the receiver.

Examples

42 class            // => Integer
"hello" class       // => String
doesNotUnderstand: selector args: arguments

Handle messages the receiver does not understand. Override for custom dispatch.

Examples

42 unknownMessage   // => ERROR: does_not_understand
perform: selector withArguments: arguments

Send a message dynamically with an arguments list.

Examples

42 perform: #abs withArguments: #()   // => 42
performLocally: selector withArguments: arguments

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)
perform: selector withArguments: arguments timeout: timeoutMs

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