Keith Schacht’s Weblog

Subscribe

📄 Ruby Sorbet is too verbose, can the syntax be improved?

29th October 2024

Awhile back when I was ramping up on Typescript, I was leaning into the benefits of types. In the Ruby world, Sorbet is the most common way to add types so I gave that a shot. In the end, I ripped it out. I spent more time wrangling type checking then the time it spent catching bugs, and one of the issues was the verbose syntax. But recently I came up with a novel solution to this problem. First, here is the verbose syntax — you end up declaring all your arguments twice:

sig { params(name: T.untyped, nickname: String).returns(Integer) }
def greet(name, nickname)
  puts "Hello, #{name}! Your nickname: #{nickname}"
  name.length
end

It may not seem like a big deal, but every time you change the name of an argument or change the order, you have to do it in two places. Recently I had an idea: could we do it in one line if we used Ruby to redefine how methods are defined? I got this syntax working and threw it up on a gist:

# Two positional arguments. The first, name, is untyped.
# The second, nickname, must be a String

df :greet,  :name, nickname: [String], returns: Integer do
  puts "Hello, #{name}! Your nickname: #{nickname}"
  name.length
end

Here is a gist. It supports positional and named arguments. I got it working with runtime and static analysis. I don’t plan to take this experiment any further right now, but maybe it’s useful to someone.

More recent articles

This is Ruby Sorbet is too verbose, can the syntax be improved? by Keith Schacht, posted on 29th October 2024.

Previous: Rails migrations can include an up_only part