November 23, 2019·4 min read·engineeringrubykeywordscompatibility

Ruby 2.7 preview 3 makes keyword intent explicit

Ruby 2.7 preview 3 focuses on keyword-argument compatibility. Its warnings identify calls that depend on converting between a positional hash and keyword arguments.

A hash at the end of a method call can mean one positional value or a set of keyword arguments. Ruby's automatic conversion has allowed the same call syntax to cross that boundary depending on the callee's parameters. Ruby 2.7.0 preview 3, released November 23, is aimed particularly at confirming compatibility around the planned separation of those argument forms.

Ruby 2.7 warns about conversions that are planned for removal in Ruby 3. The preview therefore has a transitional job. Existing code can still reach an operation through some deprecated conversions while receiving information about where its calling convention needs to become explicit. The final 2.7 release remains planned for December.

I like Ruby's readable method calls, especially when their syntax communicates the operation directly. A call that changes interpretation according to a distant signature is harder to read locally. Making the argument boundary explicit is a reasonable improvement, although the transition affects libraries that have relied on the previous conversion rules.

A hash value is not automatically a keyword list

Consider a method with a named keyword parameter and a hash containing the desired value. The preview release notes describe the first call as deprecated and the second as explicit.

def render_label(prefix: "Item")
  prefix
end

options = {prefix: "Record"}
render_label(options)
render_label(**options)

The double splat states that the hash supplies keyword arguments. Without it, the call passes a positional hash and depends on the conversion to satisfy the keyword parameter. The distinction concerns how the argument crosses the call boundary, even though both forms may produce the same result during the transition.

That is why a warning can matter before the application fails. The result remains available because Ruby 2.7 still performs the deprecated conversion. The warning identifies an implicit interpretation that the future calling convention will no longer supply. Treating the warning as irrelevant because the current test passes would miss its purpose.

The preview 3 NEWS file also describes the converse case. A method with required positional parameters can receive keywords that Ruby converts into a positional hash to fill a missing argument. The explicit repair is to pass a hash as a positional value when that is what the method expects.

A migration needs to connect each warning with the method signature and the value the caller intended to supply. Searching for hashes at the end of calls cannot establish that intent on its own. Adding ** everywhere would assign keyword meaning to values that may intentionally be positional data. The repair should preserve the intended argument category.

The proposal addresses accumulated corner cases

Yusuke Endoh's keyword-argument proposal describes the earlier design as a compatibility choice that produced many unintuitive cases. Its initial explanation separates positional hashes from keyword arguments and proposes a warning period before the new semantics. The preview turns that migration idea into behavior application authors can exercise.

This is an interface problem rather than a distinction in the contents of the hash alone. Two hashes can contain identical keys and values while serving different roles in a call. One may be the record being processed, and the other may describe options for processing it. The method signature and call syntax need to preserve that distinction.

The historical proposal is useful for the motivation, but the preview's release notes are the appropriate reference for its current behavior. A long-running discussion includes alternative designs. Reading an early example as the final specification would confuse the argument for a change with the implementation available in this preview.

I find the explicitness valuable at library boundaries. Application code can often update a method and all its callers together. A public gem may have callers it cannot see, so a warning period gives those consumers evidence about the exact calls requiring attention.

Mixed keys and empty hashes expose the distinction

The preview documents another deprecated behavior when a method accepts particular keywords but no general keyword rest parameter. A hash containing both symbol and non-symbol keys can be split between positional and keyword arguments. The notes recommend passing separate hashes or explicit arguments to preserve the intended categories.

That case shows why identifying keywords only by the presence of symbol keys is insufficient. A data hash may legitimately use symbols as data keys. Splitting it according to the callee's signature can change the value the caller thought it was passing. An explicit boundary keeps the entire positional record intact when that is the intended contract.

Empty hashes expose a related difference. The preview notes that an empty keyword splat no longer supplies an empty positional hash to a method that does not accept keywords, except for a transitional required-parameter case that warns. No keyword arguments and one positional empty hash are distinct calls.

This matters to a wrapper because dropping an empty argument can change arity. A wrapper forwarding argument collections has to preserve whether it received a positional value or keyword information. Looking only at the resulting hash contents loses that distinction precisely when the contents are empty.

Some hash-oriented calls remain intentional

The notes explicitly preserve calls using keyword-like syntax for a method that accepts only an options hash. Such a method can still receive that syntax as a positional hash without the same warning. The separation is therefore not a claim that every existing options-hash API must become a keyword API.

The preview also allows **nil in a method definition to reject keyword arguments explicitly. That gives a method with positional data a way to state that it has no keyword contract. The definition can make the intended boundary visible instead of depending on an accidental conversion rule.

Warning presentation remains unsettled on November 23. The announcement notes discussion of disabling deprecation warnings by default or suppressing duplicate warnings, with no final decision yet. That is distinct from the calling-convention work itself. Application feedback on preview 3 can identify which conversions occur, while the project continues deciding how the final release will present that feedback.