ruby / ruby/rbs

Add Support for Non-Symbol Keyowrds

Open
#1,645 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
2.2k
Forks
256
Avg merge
6d 17h
Merged PRs (30d)
37

Description

(Originally posted as a discussion, #1609, I think this is better as an issue)

While working on Kernel#system, I came across a limitation of RBS: it only lets you specify symbol keyword arguments, and not any other type.

Normal keyword arguments in Ruby are passed via key: value, such as gets(chomp: true). However, this syntax is actually sugar for gets(:chomp => true), and Ruby is capable of accepting other values for keys.

Take this contrived example:

def add_one(**kw)
  raise ArgumentError, "missing `0`" unless kw.key?(0)
  raise ArgumentError, "unknown keywords: #{kw.keys - [0]}" unless kw.keys == [0]
  kw[0] + 1
end
p add_one(0 => 3) #=> 4

Or this slightly-less-contrived example:

def add_exponentiated_numbers(**kwargs)
  sum = 0
  kwargs.each do |key, value|
    sum += key ** value
  end
end

puts add_exponentiated_numbers 2=>3, 4=>5, 6=>7 #=> 280968

There's no real way to typecheck this currently in RBS, as RBS only supports symbols for hash keys. It does have a **rest parameter, but that expects symbols as hash keys as well.

I propose we add two new pieces of syntax to function declarations:

  • <literal> => <type>, such as def add_one: (0 => Integer).
  • **<type> => <type>, such as def add_exponentiated_numbers: (**Integer => Integer).

Notably, the ** variant isn't equivalent (nor replaces) the current **<type> <variable> syntax. For example, a simplified Kernel#system (which can take integers for hash keys, which correspond to hash descriptors) could be defined as:

def system: (String cmd, **Integer => Integer, **untyped other_options) -> bool

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No implementation files or tests are named. Start by reviewing RBS's existing keyword and **rest-parameter syntax, then compare the proposed literal-key and typed-key forms with the Kernel#system and add_exponentiated_numbers examples. Done means valid signatures can express non-symbol keyword keys without replacing existing syntax, with coverage for the examples.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.