Repository navigation
Conversation
ksss
force-pushed
the
lazy-comment-string
branch
2 times, most recently
from
October 17, 2026 13:34
3e847f6 to
0b1792b
Compare
The parser used to materialize the text of every comment as a Ruby String, which duplicated the comment bytes that the Buffer already holds. Parsing core/ + stdlib/ allocated 4.1MB of such strings, about 20% of the whole AST, while consumers rarely need all of them at once: Environment and DefinitionBuilder only carry them through, and Steep reads a handful on demand (hover, completion). `RBS::AST::Comment#string` is now computed on first access from `location.source`, mirroring `parse_comment_lines` in src/parser.c (drop indentation, `#`, one following space; CRLF's CR is not part of the token, a bare CR is kept). `Comment.new(string:)` keeps working for callers that build comments by hand. To stop the C translation from building the string, config.yml gains a per-field `expose_to_ruby: false` option: the field stays in the C struct and in the serialized form, but is not passed to the Ruby constructor. The WASM deserializer honors the same flag by reading and discarding the field, so both construction paths produce identical objects. Measured on core/ + stdlib/ (252 files): memsize 20.76MB -> 16.62MB, process RSS delta 45.0MB -> 40.7MB. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ksss
force-pushed
the
lazy-comment-string
branch
from
October 17, 2026 13:35
0b1792b to
8bb5d7d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
RBS::AST::Comment#stringis now computed on first access fromlocation.sourceinstead of being materialized by the parser for every comment. The parser used to build a Ruby String for each comment, duplicating bytes theBufferalready holds, while consumers rarely need all of them at once:EnvironmentandDefinitionBuilderonly carry them through, and Steep reads a handful on demand (hover, completion). Materializing every comment up front pays for text that is mostly never looked at, and the lazy version makes the first access of each comment pay instead.To stop the C translation from building the string,
config.ymlgains a per-field optionexpose_to_ruby: false: the field stays in the C struct and in the serialized form, butast_translation.cdoes not pass it to the Ruby constructor. The WASM deserializer honors the same flag by reading and discarding the field, so both construction paths produce identical objects. The C library, the Rust crate and the serialization format are unchanged.Measurements
Both numbers below are from the benchmarks in this repository, run on
masterand on this branch with the same Ruby (4.0.6) and the samerbs collection.benchmark/memory_new_env.rb(core)StringRBS::LocationArray/Types::Function/Hash/MethodTypebenchmark/memory_new_rails_env.rb(Railsrbs collection, 93 gems)StringRBS::LocationArray/Types::Function/Hash/MethodTypeThe whole difference is in
String; every other class is byte-identical. The smaller ratio for the Rails collection reflects that gem signatures carry far less documentation than core.Process RSS and wall time (without memory_profiler)
new_envNo
Comment#stringis called while building anEnvironment, so the lazy path adds no work there.Compatibility
Comment.new(string:, location:)keeps working;string:is now optional, and a comment built without either raises onstring.parse_comment_linesinsrc/parser.c, including CRLF (the CR is not part of the comment token) and bare CR (kept). Verified by comparing the lazily reconstructed string against the previously materialized one for all 7,607 comments in core + stdlib, plus new tests for CRLF, bare CR, indentation and#without a following space.Location#source, so no second copy of the text is memoized on theLocationafter the first access.@stringisniluntil first access; code inspecting the ivar directly (the WASM round-trip test did) sees that change.🤖 Generated with Claude Code