ruby / ruby/rbs

Question about the intended semantics for inline `#:` type assertions on local variables

Open
#3,030 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
2.2k
Forks
256
Avg merge
6d 17h
Merged PRs (30d)
37

Description

Now that inline RBS comments are in ruby/rbs I'd like to clarify what the #: type assertion on a local variable is supposed to mean and to make sure that we aren't baking in a semantic difference between steep and sorbet.

For instance in the following code:

x = "hi" #: String
x = 5
  • Steep (verified on 2.0.0) treats #: as a type assertion on the expression (introduced in Steep 1.3 as "declaring the type of an expression inline, without introducing a new local variable with a @type var annotation"). The local remains flow-typed, so the later x = 5 re-infers x to Integer — no error at the reassignment.
  • Sorbet (verified on 0.6.13327 (RBS comments support) lowers x = v #: T to x = T.let(v, T). T.let declares the local's type for the whole method scope, so x = 5 is an error ("Incompatible assignment to variable declared via let").

This is extra confusing because in the case of

class Foo
  attr_accessor :bar #: String?
end

foo = Foo.new
Foo.bar = 5

results in an error in both Steep and Sorbet.

Questions

  1. Is the semantics of a #: assertion on a local variable intended to be an expression-level assertion (Steep's behavior), a scope-level declaration/pin (Sorbet's T.let behavior), or is it deliberately left to each checker?
  2. If it's left to checkers by design, can we consider documenting that (e.g. in docs/) so tool authors and users know portability is not guaranteed here?
  3. If a single intended meaning is desired, is there a preference — and would it be worth a note in the inline-syntax docs so Steep/Sorbet/other implementations (RubyMine, and third-party checkers) can converge?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the inline-syntax documentation in docs/ and the reported Steep and Sorbet behaviors for local-variable assertions. Compare the examples in the issue and determine whether the project should specify one semantic or document checker differences. Done means a documented decision or a clearly scoped documentation change for tool authors and users.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
documentation
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.