rbs icon indicating copy to clipboard operation
rbs copied to clipboard

How to deal with dynamic classes

Open HoneyryderChuck opened this issue 5 years ago • 7 comments

As one core meta-programming feature from ruby is enhancing of existing classes, or even the creation of anonymous new ones, I'm wondering whether this is possible already. Something like:

module Ext
  def foo;end
end

class A
  def self.enhance
    Class.new(self) do
      include Ext
    end
  end
end

How could one type the result of calling .enhance?

HoneyryderChuck avatar Oct 17 '20 14:10 HoneyryderChuck

I think you can use an intersection. Since you're returning a class, I think singleton is what you want:

def self.enhance: () -> singleton(A & Ext)

marcandre avatar Oct 18 '20 20:10 marcandre

That could work. But how can I make it work for "any subclass of A"?

HoneyryderChuck avatar Oct 19 '20 00:10 HoneyryderChuck

Oh, right. Replace A with self:

def self.enhance: () -> singleton(self & Ext)

I didn't try it and I'm just starting to get acquainted with RBS. Maybe it's singleton(A) & singleton(Ext), or maybe both are the same, I don't know 🤷‍♂️

marcandre avatar Oct 19 '20 00:10 marcandre

I'm getting errors on a bit of a different use-case, but similar syntax. So, for that example above:

module Ext
 def self.enhance(klass)
    Class.new(klass) do
      include Ext::InstanceMethods
    end
  end

  module InstanceMethods
    def bar;end
  end
end

Now, if I type it like this:

module Ext
  def self.enhance: (singleton(A)) -> singleton(A)
end

When running the runtime type checker on:


class A
  def foo; ; end
end

B = Ext.enhance(A) #=> this works
C = Ext.enhance(B) #=> this blows: RBS::Test::Tester::TypeError: TypeError: [.enhance] ArgumentTypeError: expected `singleton(::A)` but given `#<Class:0x000055970ae64258>`

I didn't try it and I'm just starting to get acquainted with RBS.

Likewise :)

HoneyryderChuck avatar Oct 19 '20 01:10 HoneyryderChuck

It's taking your A literally. You need [A]. Maybe this would work:

module Ext
  def self.enhance: [A] (singleton(A)) -> singleton(A) & singleton(Ext::InstanceMethods)
end

marcandre avatar Oct 19 '20 02:10 marcandre

Yeah, it's not supported at all.

Class.new(klass) do
  include Ext::InstanceMethods
end

The code requires a concept of type of a class object which includes a module... I don't think we can implement it now.

soutaro avatar Oct 19 '20 10:10 soutaro

:( sad to hear, but it's understandable that one can't ship everthing in one go.

Do you have ideas on how this could look like in the future?

HoneyryderChuck avatar Oct 20 '20 11:10 HoneyryderChuck