8

Sorbet is showing an error for the attr_reader, but correct me if I am wrong, sigs are required when the function is declared, not called, right?

I have tried going through the documentation but all I got is this note

Note: Many Ruby constructs that look like local variables are actually method calls without parens! Specifically, watch out for attr_reader and zero-argument method definitions.

app/util/hodor.rb:125: This function does not have a `sig` https://sorbet.org/docs/error-reference#7017
     125 |  attr_reader(:collection_name)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jaredsmith
  • 7,306
  • 3
  • 20
  • 31
Utkarsh Bhimte
  • 325
  • 2
  • 12
  • Where does this line of code appear? They normally are contained in class or module definitions. – Peter Camilleri Jun 19 '19 at 13:25
  • Hm, sorbet playground doesn't give this error – Sergio Tulentsev Jun 20 '19 at 15:53
  • 3
    This error is silenced in all strictness levels below `# typed: strict`. The playground defaults to `# typed: true` if no sigil is given. In all other places Sorbet defaults to `# typed: false` if no sigil is given. https://sorbet.org/docs/static – jez Jun 20 '19 at 22:33

3 Answers3

8

The error does not have to do with the attr_reader method itself needing a sig, but with :collection_name. The signature for attr_reader is already known, but the new method it dynamically creates, #collection_name does not have a known sig, and Sorbet expects this to be the place where you give it one.

You can do this to fix it:

sig { returns(String) }
attr_reader(:collection_name)
jaredsmith
  • 7,306
  • 3
  • 20
  • 31
  • 1
    Is it correct that an `attr_reader` that defines multiple attributes will have to be split up over multiple lines to make the signatures work correctly? – Philipp Hansch Jun 26 '19 at 15:33
2

Here's the Sorbet documentation on it:

It goes something like this:

# typed: true
class A
  extend T::Sig

  sig {returns(Integer)}
  attr_reader :reader

  sig {params(writer: Integer).returns(Integer)}
  attr_writer :writer

  # For attr_accessor, write the sig for the reader portion.
  # (Sorbet will use that to write the sig for the writer portion.)
  sig {returns(Integer)}
  attr_accessor :accessor

  sig {void}
  def initialize
    @reader = T.let(0, Integer)
    @writer = T.let(0, Integer)
    @accessor = T.let(0, Integer)
  end
end
Rimian
  • 36,864
  • 16
  • 117
  • 117
0

attr_reader(attribute) is the equivalent of :

def attribute
  @attribute
end

This is probably why Sorbet is asking for a sig.

user11659763
  • 183
  • 8