How to deal with dynamic classes
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?
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)
That could work. But how can I make it work for "any subclass of A"?
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 🤷♂️
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 :)
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
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.
:( 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?