-
Notifications
You must be signed in to change notification settings - Fork 220
Add type arguments support to singleton types #2502
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add type arguments support to singleton types #2502
Conversation
@soutaro Did |
06d9ce0
to
46c9aa2
Compare
Previously, singleton type arguments could not be supported by RBS. This adds support for them, enabling syntax like `singleton(Array)[String, Integer]`.
46c9aa2
to
91eafe8
Compare
@allcre Can you give me some examples why we need that type? I'm assuming |
@soutaro we use it in Sorbet to represent the type of the attached class to a singleton. It's useful around factories, here's a simple example: class Box
extend T::Sig
extend T::Generic
E = type_member
sig { params(e: E).void }
def initialize(e)
@e = e
end
sig { returns(E) }
def e
@e
end
end
extend T::Sig
sig { returns(T.class_of(Box)[Box[Integer]]) }
def example
Box
end
x = example
T.reveal_type(x) # => T.class_of(Box)[Box[Integer]]
x.new("str") # error: Expected `Integer` but found `String` for argument `e` More involved examples can be found in the documentation: https://sorbet.org/docs/class-of#tclass_of-applying-type-arguments-to-a-singleton-class-type. |
RBS expects us to genericize class methods because it only recognizes type parameters at the instance level. class Set[E]
def self.[]: [E] (*E elements) -> Set[E] # `E` is totally not duplicated
end Honestly, that might be a flawed design: class Set[E]
def self.[]: (*untyped elements) -> instance # `instance` is `Set[untyped]`!
end |
Thanks @Morriar, I got the use case and agree that it cannot be written in RBS now. Using an interface would be a workaround, but not sure if it can cover the existing use cases. Let me confirm the semantics: the type What should we do for the other singleton methods? class Box[T]
def initialize: (T) -> void
def self.new_array: [T] (T) -> Box[Array[T]]
end
b = Box #: singleton(Box)[String]
b.new("") # => Box[String]
b.new(1) # => type error
b.new_array(1) #=> ??? Looks like it only works for |
How about changing the semantics so that type parameters apply on the class level as well? class Box[T]
def self.new_array: (T) -> Box[Array[T]] # No need to genericize the method separately
def self.[]: (T) -> instance # `instance` was `Box[untyped]`, but now `Box[T]`
end |
@ParadoxV5 Yeah, it would make sense. But, how can we associate the type parameter |
Allowing |
Add support for parameterized singleton types
This PR adds support for type parameters on singleton types to match the functionality available in Sorbet's
T.class_of(X)[Y]
syntax. With this change, RBS now supports the equivalent syntax:singleton(X)[Y]
.Changes
Examples
Previously, only this was supported:
Now this is also supported:
Questions
Should the
Application
module be included in theClassSingleton
class, similar to how it's included inClassInstance
andInterface
? Currently, I've implemented the necessary methods directly.Are there additional methods such as
map_type
andeach_type
that should be added to theClassSingleton
class?