From: "bkuhlmann (Brooke Kuhlmann) via ruby-core" Date: 2023-01-03T23:48:53+00:00 Subject: [ruby-core:111611] [Ruby master Bug#19301] Fix Data class to report keyrest instead of rest parameters Issue #19301 has been updated by bkuhlmann (Brooke Kuhlmann). Yeah, let me respond in order: 1. Correct. No issues there. 2. Correct. My problem was thinking in terms of pure Ruby, not C. That was my source of confusion, originally, but you've resolved my confusion. 3. Correct. However, I think there is still an outstanding issue, architecturally, but I'll explain shortly. 4. Thanks, yes, I read your article in detail and linked to it from my [Ruby Data](https://www.alchemists.io/articles/ruby_data) article as well. I understand more clearly where you are coming from *but* am still concerned how to dynamically build a proper argument array when `Struct#initialize` and `Data#initialize` always return `[[rest]]` for parameters. I now realize that is how C-backed objects work but that also means `Method#parameters` is unreliable in terms of dealing with `Struct` and `Data` classes. For example, consider the following: ``` ruby DataExample = Data.define :one, :two StructAny = Struct.new :one, :two StructKeywordOnly = Struct.new :one, :two, keyword_init: true models = [DataExample, StructAny, StructKeywordOnly] arguments = [{one: 1, two: 2}] models.each do |model| print "#{model}: " puts model[*arguments] rescue ArgumentError => error puts error.message end # DataExample: missing keyword: :two # StructAny: #1, :two=>2}, two=nil> # StructKeywordOnly: # ``` In all three models, asking `model.method(:initialize).parameters` will always answer `[[rest]]` for parameters so when I build my arguments (i.e. `[{one: 1, two: 2}]`) in the same format as dictated from the `Method#parameters` response then the only model that gives me the correct instance is the `StructKeywordOnly` model because using `keyword_init: true` does that coercion for me. ���� I originally logged this issue because I was thinking `Data` should behave more like how a `Struct` works when used with `keyword_init: true` since `Data` enforces keyword arguments for `#initialize` by default but I think this is a bigger issue than `Data` alone. Would it be better if I move this discussion to a new issue where the focus is on asking if `Method#parameters` could properly answer the argument signature for C objects? Maybe that's too big of an ask? ---------------------------------------- Bug #19301: Fix Data class to report keyrest instead of rest parameters https://bugs.ruby-lang.org/issues/19301#change-100981 * Author: bkuhlmann (Brooke Kuhlmann) * Status: Rejected * Priority: Normal * ruby -v: ruby 3.2.0 (2022-12-25 revision a528908271) [arm64-darwin22.2.0] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- ## Overview Hello and Happy New Year. ���� With the new `Data` class, I'm seeing a discrepancy in parameter behavior compared to a `Struct`. I understand the original `Data` [feature](https://bugs.ruby-lang.org/issues/16122) request made design choices to only accept keyword arguments for the `#initialize` method but reporting `[[rest]]` parameters seems misleading to me because it doesn't share the more flexible `Struct#initialize` behavior and would like to request `Data#initialize` answer `[[keyrest]]` for parameters for improved metaprogramming accuracy. ## Steps to Recreate To reproduce, consider the following: ``` ruby DataExample = Data.define :one, :two StructExample = Struct.new :one, :two argument_array = [one: 1, two: 2] argument_hash = {one: 1, two: 2} puts "Data (parameters): #{DataExample.method(:initialize).parameters}" puts "Struct (parameters): #{StructExample.method(:initialize).parameters}" puts "Data (argument hash): #{DataExample[**argument_hash]}" puts "Struct (argument array): #{StructExample[*argument_array]}" puts "Struct (argument hash): #{StructExample[**argument_hash]}" ``` The above will output the following: ``` Data (parameters): [[:rest]] Struct (parameters): [[:rest]] Data (argument hash): # Struct (argument array): #1, :two=>2}, two=nil> Struct (argument hash): # ``` The `Struct` class -- as far as I know -- has always reported `[[rest]]` parameters even though it can accept positional or keyword arguments without error. ...but *this is definitely not the case with* the `Data` class which can be seen when running the following modification to the above: ``` ruby DemoExample[*argument_array] # missing keyword: :two (ArgumentError) ``` The above clearly betrays the `[[rest]]` parameters response (granted a `Struct` is slightly devious too but at least happily accepts positional or keyword arguments). With this in mind, could `Data#initalize` be fixed to at least report `[[keyrest]]` so we'd have a better chance of metaprogramming the correct argument format based on the `#parameters` response for initializing a `Data` instance correctly? Thanks. ����������������� ## Environment `ruby 3.2.0 (2022-12-25 revision a528908271) [arm64-darwin22.2.0]` -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/