4

I have a method that returns an object which could be one of many different types of object but which are all part of the same ancestor class. The precise object type is inferred dynamically.

However, I'm confused as to what to put for the return value in the signature. I've put a placeholder below using instance_of to illustrate the problem:

sig{params(instance_class: String).returns(instance_of ParentClass)}
def build_instance instance_class
  klass = Object.const_get(instance_class)
  return klass.new
end

Given that I don't know which precise class will be returned (and I'd prefer not to list them explicitly) but I do know that it will be a subclass of ParentClass is there a way in Sorbet to specify this? I could use T.untyped but it's unnecessarily loose.

Peter Nixey
  • 16,187
  • 14
  • 79
  • 133

1 Answers1

4

Through trial and error I've discovered that checking that the object includes the type in its ancestors is, if I understand correctly, sorbet's default behaviour.

Sorbet won't check that the object precisely matches the specified Type, only that it includes that type in its ancestors (perhaps this is what Typechecking in general means but I'm fairly new to the game).

To avoid the following error though:

Returning value that does not conform to method result type https://srb.help/7005

you also need to T.cast() the object that you return to the ParentClass:

sig{params(instance_class: String).returns(ParentClass)}
def build_instance instance_class
  klass = Object.const_get(instance_class)
  # NB instance is a descendent of ParentClass, not an instance...
  return T.cast(klass.new, ParentClass)
end

This seems to work but I'd love to know whether it's the correct way to solve the problem.

Peter Nixey
  • 16,187
  • 14
  • 79
  • 133
  • Yeah, what you have is correct. `returns(ParentClass)` means returning an instance of ParentClass (read: "return a ParentClass"). An instance of a descendent of ParentClass is also an instance of ParentClass. You can check `klass.new.is_a?(ParentClass)` and it should return true. Sorbet raised the error 7005 because it doesn't know whether `klass` is a subclass of ParentClass, due to it being retrieved from `Object.const_get`. – hdoan Jul 22 '20 at 15:53
  • @hdoan - that's super, thanks so much. And thanks for the great work with Sorbet itself - it's awesome to be able to use it. Are you guys planning to release any IDE plugins to help with autocompletion during development? – Peter Nixey Jul 22 '20 at 22:25
  • 1
    Thanks! I'm working on sorbet-rails only so I can't speak for the sorbet team, but I've heard that they are actively working on the IDE plugin (VSCode). Stay tuned! – hdoan Jul 23 '20 at 04:55
  • Splendid news – Peter Nixey Jul 24 '20 at 07:13
  • Oh and thanks for the sorbet-rails work too, I’d have been stuffed without it! – Peter Nixey Jul 24 '20 at 07:14