I want to extend the standard Array with a new instance method but I keep getting a runtime error about the type_member not being found.
The definition looks like this.
class Array
extend T::Sig
extend T::Generic
sig do
type_parameters(:U)
.params(split_elem: T.type_parameter(:U))
.returns(T::Array[Elem])
end
def split_on(split_elem)
output = []
group = []
each do |elem|
if elem.eql?(split_elem)
output << group unless group.empty?
group = []
else
group << elem
end
end
output << group unless group.empty?
output
end
end
Is there a way to explicitly require the rbi file declaring Elem?
When trying to run the code, I get the following error. I have tried requiring the sorbet-runtime but no success so far.
NameError: uninitialized constant Array::Elem
.returns(T::Array[Elem])
RBI files are purely static artifacts, they are not meant to be required or run in any way. So, the high-level answer to your question is "no, you can't require RBI files".
The problem you are facing is that you are adding a signature that is statically checkable (i.e. Sorbet can understand
Elemand type-check your code without running it), but it is not valid at runtime, since there is no actualElemconstant under the RubyArrayclass.There are three ways you can square this circle:
T.self_typeas the return type, which will solve your problem withElem. Docs forT.self_typeare here.Array#split_onto an RBI file, which will make the signature checked only statically (based on what I said about RBI files above), orT::Sig::WithoutRuntime.siginstead ofsigto write your signature, as explained here.