ruby / rbs

Type Signature for Ruby
Other
1.94k stars 208 forks source link

Cannot specify type variables for `instance` #1521

Open ParadoxV5 opened 11 months ago

ParadoxV5 commented 11 months ago
class MyWrapper[E]
  def self.of: (E) -> instance # RBS::UnknownTypeName (it’s not inferred from `MyWrapper[E]`)
  def self.of: (E) -> instance[E] # RBS::SyntaxError
  def self.of: [E] (E) -> instance # ok, but `[E]` is not used in practice (it’s not the same `[E]` as the one in `MyWrapper[E]`)
  def self.of: (untyped) -> instance # ok, but `untyped` is bad
end

Even Steep is aware of this limitation: https://github.com/soutaro/steep/blob/v1.5.3/lib/steep/subtyping/check.rb#L307

Proposal: instance[E]?

The problem might be significant for class as well: https://github.com/soutaro/steep/blob/v1.5.3/lib/steep/subtyping/check.rb#L322

soutaro commented 11 months ago

I know there are some cases that requires that kind of types, but we don't have a plan to support it at least for now.

A class inheriting from a generic class may be non-generic, and what can we do for instance[T] (and maybe self[T]) types?

class Generic[T]
  def foo: () -> instance[Array[T]]
end

class NonGeneric < Generic[String]
end

# Even worse if it inherited by another generic class.
class AnotherGeneric[T] < NonGeneric
end
ParadoxV5 commented 11 months ago

def self.of: (E) -> instance # RBS::UnknownTypeName (it’s not inferred from `MyWrapper[E]`)

How about letting class methods pick up generics?

ParadoxV5 commented 11 months ago

def self.of: (E) -> instance # RBS::UnknownTypeName (it’s not inferred from `MyWrapper[E]`)

How about letting class methods pick up generics?

Would this rather be a Steep job? Unless the RBS gem itself also involved…

soutaro commented 11 months ago

How about letting class methods pick up generics?

Generics in RBS currently is for instance types.

I think no other programming language allows this. Do you know any example?

soutaro commented 11 months ago

The type you want would be this?

def self.of: [E, T < MyWrapper[E]] (E) -> T

Steep allows explicit type application, and it will help:

MyWrapper.of(123) #$ Integer, AnotherWrapper         # E=Integer, T=AnotherWrapper
ParadoxV5 commented 11 months ago

The type you want would be this?

def self.of: [E, T < MyWrapper[E]] (E) -> T

Almost. The strength of instance is that it indicates the ::of of MyWrapperSubclass[E] < MyWrapper[E] returns a MyWrapperSubclass[E] and not an unspecific MyWrapper[E].

Steep allows explicit type application, and it will help:

MyWrapper.of(123) #$ Integer, AnotherWrapper         # E=Integer, T=AnotherWrapper

Good to know more :+1:. Steep really lacks detailed and locatable docs for Ruby annotations, both in-line and #@type styles.