Best practice for handling mixin module unknown methods / possible syntax to declare it - Ruby sorbet

Problem

Mixin modules can refer to methods that don't exist in the module, but if we know what concrete classes they will be used in can there be a way to declare that?

eg this code:

module ActiveRecordBarExtension
  def bar
    puts "hello"
    save!
  end
end

ActiveSupport.on_load :active_record do
  include ActiveRecordBarExtension
end

Sorbet will correctly say that save! does not exist. We humans know it will exist.

I think this StackOverflow covers this too, but there wasn't a specific Sorbet answer.

Proposed solution

I suspect that the current solution is to declare the missing save! as an abstract method. However, it could be more clear if we specified the class that will include the module instead. That way we get all the instance methods for the real class (which will update automatically on upgrades), and documentation (and enforcement?) of what class it should be in.

Could we say something like:

module ActiveRecordBarExtension
  # NB, this method does not exist yet:
  T.included_into(ActiveRecord)

  def bar
    puts "hello"
    save!
  end
end

I can well imagine there problems (concrete and theoretical) with this. It may be that we don't want to enforce on people how and where a module should be used. I can guess that if this was a "good idea" it would have been done by now.

How does Stripe "do mixins"? Do you use ActiveSupport::Concerns much for example?

Asked Oct 12 '21 10:10
avatar hlascelles
hlascelles

2 Answer:

This looks like the feature proposed in https://github.com/sorbet/sorbet/pull/3409

1
Answered Jan 06 '21 at 16:58
avatar  of Morriar
Morriar

It is exactly that :facepalm:. That will teach me to search issues but not pull requests. Thanks!

1
Answered Jan 06 '21 at 19:25
avatar  of hlascelles
hlascelles