Open mtsmfm opened 1 month ago
:up: for something (not necessarily this)
From https://github.com/soutaro/steep/pull/905#issuecomment-1977213468, the current solution is
class Object
def nil?: () -> bool # cannot be assertively `false` or else `NilClass#nil?` breaks polymorphism of `NilClass < Object`
end
class NilClass
def nil?: () -> true
end
Or, with https://github.com/ruby/rbs/discussions/1639#discussioncomment-7648121,
class Object
def nil?: [self < nil] () -> true
| () -> bool
end
But in either case, the prickly part is that there’s no format to tell that non-nil
s’ #nil?
always return false
. In pseudocode, we need:
class Object
def nil?: [self < nil] () -> true
| [self !< nil] () -> false # ⬅ a way to declare a negative constraint
end
Alternatively, if the overload semantics changes so that earlier branches subtractively narrow latter branches,
class Object
def nil?: [self < nil] () -> true
| () -> false # `else`
end
https://docs.python.org/3.13/library/typing.html#typing.TypeIs Y'all were talking about adding
pure
to RBS for type narrowing predicates before, perhaps this would work instead? ⸺@DanielPechersky, on Ruby Discord
Ref: https://github.com/soutaro/steep/issues/472
Currently RBS doesn't have any syntax to narrow types in control flow.
So there's no way to achieve the following:
But actually, both Sorbet and Steep treat some special methods to narrow types
https://github.com/sorbet/sorbet/blob/718bc64f895abeeff88f56efbc92a3554ffaa4f2/infer/environment.cc#L536-L545
https://github.com/soutaro/steep/blob/a868762c2bd09f0954b05cdd9eab1819e14a51d3/lib/steep/interface/builder.rb#L709-L721
Ideally, I think we need to have a syntax considering Ruby gems which extend
Object
like ActiveSupport'spresent?
.I'm not very familiar with type system though, I guess the syntax would be similar with TypeScript's type predicates
https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates