Skip to content

Migrate example value classes from Object to Value subclass#1028

Merged
jamesc merged 3 commits intomainfrom
worktree-docs/sicp-to-value
Mar 1, 2026
Merged

Migrate example value classes from Object to Value subclass#1028
jamesc merged 3 commits intomainfrom
worktree-docs/sicp-to-value

Conversation

@jamesc
Copy link
Owner

@jamesc jamesc commented Mar 1, 2026

Summary

  • Migrates SchemeSymbol, SchemeLambda, Message, and Transaction from Object subclass: to Value subclass:, making immutability intent explicit per ADR 0042
  • Drops manual getters and custom equality that Value auto-generates
  • Renames get* accessors on Message/Transaction to bare field names (text, sender, amount, etc.) — idiomatic Beamtalk style — with matching test updates
  • Refactors SchemeEval's special-form string dispatch from 8 repeated (sym =:= "x") ifTrue: chains into a match: expression via an extracted evalSpecialOrApply:tail:in: helper

Test plan

  • just build passes
  • just clippy passes
  • cargo run --bin beamtalk -- build examples/sicp/ compiles clean
  • cargo run --bin beamtalk -- test examples/sicp/ passes (one pre-existing doc-test failure unrelated to this change)
  • just test — 649 BUnit + 2208 runtime tests all green

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor

    • Converted several types (transactions, messages, lambdas, symbols) to immutable Value-based classes with auto-generated field accessors and named-parameter construction.
    • Updated constructors to named-parameter style and adjusted equality/print semantics for symbols.
    • Consolidated evaluator dispatch for special forms and function application to produce consistent return values.
  • Tests

    • Updated tests to use new accessors and construction semantics.

- SchemeSymbol, SchemeLambda: Object → Value subclass, drop manual
  getters and custom =:= (auto-generated by Value)
- Message, Transaction: Object → Value subclass, rename get* accessors
  to field names (text, sender, amount, from, to, status, timestamp)
  and update tests accordingly
- Refactor eval.bt special-form dispatch to match: expression via
  extracted evalSpecialOrApply:tail:in: helper method

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 1, 2026 11:29
@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3f5310f and 5b69fcb.

📒 Files selected for processing (1)
  • examples/sicp/src/scheme/eval.bt

📝 Walkthrough

Walkthrough

This PR converts several example classes from Object to Value subclasses (bank, chat-room, SICP), removes explicit getter methods in favor of auto-generated accessors and keyword constructors, updates tests to use new accessors, and refactors the Scheme evaluator by extracting special-form dispatch and application into dedicated methods.

Changes

Cohort / File(s) Summary
Bank Example
examples/bank/src/transaction.bt, examples/bank/test/transaction_test.bt
Convert Transaction to Value subclass, remove explicit getters (getAmount, getFrom, getTo, getTimestamp, getStatus), adopt keyword constructor and auto-generated accessors (amount, from, to, timestamp, status) and update tests accordingly.
Chat-room Example
examples/chat-room/src/message.bt, examples/chat-room/test/message_test.bt
Convert Message to Value subclass, remove getText/getSender, adopt keyword constructor and text/sender accessors; update tests and examples.
SICP: Eval Refactor
examples/sicp/src/scheme/eval.bt
Add evalSpecialOrApply: head tail: tail in: env and evalApply: head tail: tail in: env; extract special-form dispatch (quote, define, lambda, if, cond, let, and/or) into dispatcher and consolidate function-application path.
SICP: Value Class Changes
examples/sicp/src/scheme/lambda.bt, examples/sicp/src/scheme/symbol.bt
Convert SchemeLambda and SchemeSymbol to Value subclass; change SchemeLambda constructor to SchemeLambda params: p body: b closureEnv: e and remove explicit accessors; change SchemeSymbol constructor to SchemeSymbol name: n, remove name and =:= accessors and adjust representation (printString).

Sequence Diagram(s)

sequenceDiagram
actor Caller
participant SchemeEval
participant Env
participant Proc as Procedure

Caller->>SchemeEval: evalSpecialOrApply(head, tail, env)
alt head is special-form
    SchemeEval->>SchemeEval: handle special (quote/define/lambda/if/cond/let/and/or)
    SchemeEval-->>Caller: return value
else not special
    SchemeEval->>SchemeEval: evalApply(head, tail, env)
    SchemeEval->>Env: evaluate head -> procedure value
    Env-->>SchemeEval: procedure (Proc)
    SchemeEval->>Proc: evaluate args in env
    Proc-->>SchemeEval: result
    SchemeEval-->>Caller: return result
end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: migrating example value classes from Object to Value subclass, which is reflected across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch worktree-docs/sicp-to-value

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates several example-domain “record” classes to be explicit immutable value objects by migrating them from Object subclass: to Value subclass: (per ADR 0042), and refactors the SICP Scheme evaluator’s special-form dispatch to use pattern matching.

Changes:

  • Migrate SchemeSymbol, SchemeLambda, Message, and Transaction to Value subclass: and remove now-redundant manual getters / custom equality.
  • Rename Message/Transaction get* accessors to idiomatic field-name accessors (auto-generated by Value) and update example tests accordingly.
  • Refactor SchemeEval special-form dispatch into a match: expression via evalSpecialOrApply:tail:in:.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
examples/sicp/src/scheme/symbol.bt Convert SchemeSymbol to a Value type; rely on auto-generated accessor/equality; update doc examples.
examples/sicp/src/scheme/lambda.bt Convert SchemeLambda to a Value type and rely on auto-generated accessors.
examples/sicp/src/scheme/eval.bt Replace repeated special-form if-chains with match: dispatch via evalSpecialOrApply:tail:in:.
examples/chat-room/src/message.bt Convert Message to Value subclass: and remove manual get* accessors; update docs.
examples/chat-room/test/message_test.bt Update tests to use text/sender accessors.
examples/bank/src/transaction.bt Convert Transaction to Value subclass: and remove manual get* accessors; update docs.
examples/bank/test/transaction_test.bt Update tests to use amount/from/to/status/timestamp accessors.

Addresses Copilot review: function-application logic was duplicated
between eval:in: (non-symbol head) and the _ arm of
evalSpecialOrApply:tail:in: (non-special-form symbol). Extracted into
evalApply:tail:in: so argument evaluation rules live in one place.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/chat-room/src/message.bt`:
- Around line 7-17: The Message type was changed to a Value subclass which
violates the file-specific rule requiring Object subclass with new: construction
semantics; revert Message to "Object subclass: Message" (not Value) and update
the example usage and documentation to use the Object/new: constructor pattern
(e.g., create via new: or whatever the project's Object API uses) instead of the
Value-style literal constructor; ensure the class declaration and the usage
examples/description (mentions of auto-generated getters, immutability lines)
consistently reflect Message as an Object subclass using new: semantics.

In `@examples/sicp/src/scheme/eval.bt`:
- Line 108: Remove the leading caret from the final expression "^sym match:" so
the method ends with an implicit return; locate the expression "^sym match:" in
the method and change "^sym match:" to "sym match:" (keeping the rest of the
expression unchanged) and ensure ^ is only used elsewhere for early returns per
Beamtalk guidelines.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1aa5989 and d875b3a.

📒 Files selected for processing (7)
  • examples/bank/src/transaction.bt
  • examples/bank/test/transaction_test.bt
  • examples/chat-room/src/message.bt
  • examples/chat-room/test/message_test.bt
  • examples/sicp/src/scheme/eval.bt
  • examples/sicp/src/scheme/lambda.bt
  • examples/sicp/src/scheme/symbol.bt

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
examples/sicp/src/scheme/eval.bt (2)

104-106: ⚠️ Potential issue | 🟡 Minor

Remove ^ from the method’s final expression.

Line 106 uses ^ on the terminal match: expression; this should be an implicit return.

✂️ Suggested fix
-    ^sym match: [
+    sym match: [

As per coding guidelines **/*.bt: “Use ^ ONLY for early returns in Beamtalk, never on last expression.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/sicp/src/scheme/eval.bt` around lines 104 - 106, In
evalSpecialOrApply (method header: evalSpecialOrApply: head tail: tail in: env
=>) remove the caret prefix on the final expression so the terminal "sym match:
[...]" is returned implicitly; ensure no other early-return uses of ^ are
removed, only the trailing ^ before the match expression should be deleted to
comply with the guideline that ^ is used only for early returns.

108-149: ⚠️ Potential issue | 🟠 Major

Add arity/shape checks for special forms before indexing tail.

quote / define / lambda / if / let currently call tail first / tail at: directly. Malformed input can surface raw index/type failures instead of evaluator-grade messages.

🛡️ Suggested validation pattern
-      "quote"  -> tail first;
+      "quote"  -> [
+        tail size =:= 1 ifFalse: [self error: "quote expects exactly 1 argument"]
+        tail first] value;
@@
       "define" -> [
+        tail size =:= 2 ifFalse: [self error: "define expects exactly 2 arguments"]
+        ((tail at: 1) class =:= SchemeSymbol) ifFalse: [
+          self error: "define expects a symbol name as first argument"]
         varName := (tail at: 1) name
         defVal  := self eval: (tail at: 2) in: env
         env define: varName value: defVal.
         nil] value;
@@
       "lambda" -> [
+        tail size =:= 2 ifFalse: [self error: "lambda expects parameters and body"]
+        ((tail at: 1) class =:= List) ifFalse: [
+          self error: "lambda expects a parameter list"]
         params := (tail at: 1) collect: [:p | p name]
         SchemeLambda withParams: params body: (tail at: 2) env: env] value;
@@
       "if" -> [
+        ((tail size =:= 2) or: [tail size =:= 3]) ifFalse: [
+          self error: "if expects 2 or 3 arguments"]
         condVal := self eval: (tail at: 1) in: env
@@
       "let" -> [
+        tail size =:= 2 ifFalse: [self error: "let expects bindings and body"]
+        ((tail at: 1) class =:= List) ifFalse: [
+          self error: "let expects a bindings list"]
         binds    := tail at: 1

As per coding guidelines examples/sicp/src/scheme/eval.bt: “Error handling should provide clear, user-friendly error messages (e.g., 'Not a procedure: X') instead of raw system crashes”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/sicp/src/scheme/eval.bt` around lines 108 - 149, The special-form
branches in the evaluator (the dispatch that matches "quote", "define",
"lambda", "if", "let" and then uses tail first/at:) lack arity/type checks and
can raise raw index/type errors; update each branch (the handlers for "quote",
"define", "lambda", "if", "let" inside the eval dispatch and the helper methods
evalCond/evalAnd/evalOr/evalApply as appropriate) to first validate tail is a
non-nil sequence of the expected length and shapes (e.g., "define" must have
exactly 2 operands and first operand must be a symbol name, "lambda" must have a
parameter list and a body, "if" must have 2 or 3 operands, "let" must have a
bindings list and a body, "quote" must have one operand) and when validation
fails raise a clear evaluator error message (e.g., "Malformed define: expected
(define name expr)") instead of letting index/type exceptions surface.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@examples/sicp/src/scheme/eval.bt`:
- Around line 104-106: In evalSpecialOrApply (method header: evalSpecialOrApply:
head tail: tail in: env =>) remove the caret prefix on the final expression so
the terminal "sym match: [...]" is returned implicitly; ensure no other
early-return uses of ^ are removed, only the trailing ^ before the match
expression should be deleted to comply with the guideline that ^ is used only
for early returns.
- Around line 108-149: The special-form branches in the evaluator (the dispatch
that matches "quote", "define", "lambda", "if", "let" and then uses tail
first/at:) lack arity/type checks and can raise raw index/type errors; update
each branch (the handlers for "quote", "define", "lambda", "if", "let" inside
the eval dispatch and the helper methods evalCond/evalAnd/evalOr/evalApply as
appropriate) to first validate tail is a non-nil sequence of the expected length
and shapes (e.g., "define" must have exactly 2 operands and first operand must
be a symbol name, "lambda" must have a parameter list and a body, "if" must have
2 or 3 operands, "let" must have a bindings list and a body, "quote" must have
one operand) and when validation fails raise a clear evaluator error message
(e.g., "Malformed define: expected (define name expr)") instead of letting
index/type exceptions surface.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d875b3a and 3f5310f.

📒 Files selected for processing (1)
  • examples/sicp/src/scheme/eval.bt

Per CLAUDE.md: use ^ only for early returns, never on last expression.
`sym match: [...]` is the method's final expression — implicit return
suffices.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jamesc
Copy link
Owner Author

jamesc commented Mar 1, 2026

Re CodeRabbit comments:

message.btValue subclass: is intentional. CodeRabbit cited a "file-specific rule requiring Object subclass" that doesn't exist. This branch's entire purpose is migrating example value classes from Object subclass: to Value subclass: per ADR 0042. The previous doc comment referencing Object subclass was simply the old text being replaced.

eval.bt^sym match: implicit return — Fixed in commit 5b69fcb. Removed ^ per CLAUDE.md ("use ^ only for early returns, never on last expression").

eval.bt — arity validation — Valid suggestion, but out of scope for this cleanup PR. The SICP evaluator is a pedagogical example, not a hardened interpreter. Filed as a separate follow-up.

@jamesc jamesc merged commit a75edb5 into main Mar 1, 2026
5 checks passed
@jamesc jamesc deleted the worktree-docs/sicp-to-value branch March 1, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants