rbs icon indicating copy to clipboard operation
rbs copied to clipboard

A way to distinguish "gradual typing" from "anything possible"

Open Strech opened this issue 1 month ago • 6 comments

Since the renaming any into untyped there is no good way semantically to separate your progress of gradual typing from the uncontrollable type.

In Datadog we build some tools to help us track gradual typing progress and we have to define our way to express situations like "this is user input and literally anything could be given".

For now, we just stick with a simplest solution to alias untyped as any and make an agreement to use any only when we can't narrow down the expected type due to its nature.

module Datadog
  type any = untyped
end

Maybe we also could use some other types for that alias like Object or BasicObject, but this is not the point.

What is your opinion on RBS providing a built-in way to distinguish "I don't have to type it now" from "I don't control the type, it could be anything" or is there a better way of doing that differentiation?

Strech avatar Nov 19 '25 10:11 Strech

It looks like you're looking for top, the super type of all types?

Here's how we use it with Sorbet:

# typed: true

#: (top) -> void
def foo(x)
  x.to_s # error: Method `to_s` does not exist on `top`
end

foo(42)
foo(nil)
foo(->() {})

#: (untyped) -> void
def bar(x)
  x.to_s # ok
end

bar(42)
bar(nil)
bar(->() {})

While top accept any type as input (all types are subtypes of top), it doesn't define any method.

Morriar avatar Nov 19 '25 14:11 Morriar

"I don't control the type, it could be anything"

untyped

"I don't have to type it now"

__todo__ from #1520 ᗡ:


P.S. Although I think every RBS prototyper spits out untyped, rather than __todo__, which suits gradual typing better?

ParadoxV5 avatar Nov 19 '25 18:11 ParadoxV5

Not just prototypers, steep stats reports untyped vs typed, as if untyped was more like __todo__.

lloeki avatar Nov 20 '25 07:11 lloeki

@ParadoxV5 that __todo__ is interesting, but has a few issues:

  • generators currently use untyped as "I don't know, I couldn't figure it out, you should look at this" i.e what would be __todo__
  • steep stats shows progress of progressive typing as "typed calls" vs "untyped calls" (i.e "these method calls happen on untyped objects, PTAL"), revealing behind-the-scenes untyped.

So let's imagine, it could be made that:

  • generators generate __todo__ instead of untyped
  • tooling such as steep stats count __todo__ instead of untyped

But then what of the swaths of code that have already been generated as untyped by previous tooling? Suddenly the shift in semantics would make them all invisible.

I would argue then that introducing a any (by this name or another) that means "not todo, I really mean it" and keeping untyped as the "TODO" one could be the safe, non-breaking move.

lloeki avatar Nov 20 '25 14:11 lloeki

Aliasing top (union of all types) as any is actually a good idea; there is even all for its opposite, bot (intersection, i.e., subtype of all types), for enabling contravariance.

ParadoxV5 avatar Nov 20 '25 23:11 ParadoxV5

I had some issues using top as a replacement for untyped in some specific case (sorry, don't have it at hand). But the idea is purely semantical with a minimum changes to the existing flow.

To keep untyped as a gradually reducing definition and any (implementation doesn't matter) as "I mean it's anything, I don't control it" definition.

Strech avatar Nov 24 '25 13:11 Strech