Feature #16806
Updated by k0kubun (Takashi Kokubun) over 4 years ago
## Proposal ```rb Post = Struct.new(:id, :name) # In addition to this, Post.new(1, "hello") #=> #<struct Post id=1, name="hello"> # Let the following initialization also work Post.new(id: 1, name: "hello") #=> #<struct Post id=1, name="hello"> ``` ### Known incompatibility * `Post.new(id: 1, name: "hello")` `Post.new(1, foo: "bar")` which was written in Ruby 2 will be behave differently * One way to save most of such use cases (continue to return `#<struct Post id=1, name="hello">` instead of `#<struct Post id={:id=>1, :name=>"hello"}, name=nil>` name={:foo=>"bar"}`) could be considering all arguments as non-keyword arguments either when there's at least one non-keyword argument (`1` in this example) or when non-member keyword argument is specified (`foo:` in this example). * Struct initialization only This is actually confusing when using keyword arguments intentionally, and it should be warned in Ruby 3.0. **This feature should be introduced in Ruby 3.1 or later.** probably print warnings if we adopt it. ### Edge cases * When keyword arguments and positional arguments are mixed: `Post.new(1, name: "hello")` * This should continue to work "hello")`: Should it behave like Ruby 2: `#<struct Post id=1, name={:name="hello"}>` 2 or raise ArgumentError? (no strong preference) * Only keywords are given but they include an invalid member: `Post.new(foo: "bar")` * ArgumentError (unknown keywords: foo) `Post.new(1, id: 1)`: Should it behave like Ruby 2, print warnings (setting `id=1, name=nil`) or raise ArgumentError? (no strong preference) * When `keyword_init` `Post.new(1, "hello")` when `keyword_init: true` is used * nil: default behavior. Positional arguments given use positional init. Keyword arguments without positional arguments treated as positional in 3.0 with warning, and treated as keyword init in Ruby 3.1. * true: Require keyword init, disallow positional init. * false: Treat keywords as positional hash. explicitly set: It should continue to be ArgumentError. ## Use cases * Simplify a struct definition where [Feature #11925] is used. * When we introduced [Feature #11925], @mame thought we don't need `keyword_init: true` once keyword args are separated (https://docs.google.com/document/d/1XbUbch8_eTqh21FOwj9a_X-ZyJyCBjxkq8rWwfpf5BM/edit#). That's what this ticket is all about. * However, the keyword arguments separation was done differently from what we expected at the moment. So we need to deal with accept the "Known incompatibility". Ruby 3.0 completing the separation would be the best timing to introduce this incompatibility if we'd like this feature. * Matz objected to having a new keyword argument (`immutable: true`) in `Struct.new` at https://bugs.ruby-lang.org/issues/16769#note-8. So `keyword_init: true` seems also against Ruby's design. Now we should be able to skip specifying the option for consistency in the language design.