From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-3.9 required=3.0 tests=AWL,BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_PASS shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id 733F21F466 for ; Thu, 16 Jan 2020 06:58:35 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 7B309120BE6; Thu, 16 Jan 2020 15:58:21 +0900 (JST) Received: from o1678948x4.outbound-mail.sendgrid.net (o1678948x4.outbound-mail.sendgrid.net [167.89.48.4]) by neon.ruby-lang.org (Postfix) with ESMTPS id C3F0C120BE4 for ; Thu, 16 Jan 2020 15:58:19 +0900 (JST) Received: by filterdrecv-p3iad2-57f487d66-lklbj with SMTP id filterdrecv-p3iad2-57f487d66-lklbj-16-5E200993-27 2020-01-16 06:58:27.589971528 +0000 UTC m=+2614308.385090528 Received: from herokuapp.com (unknown [54.158.130.18]) by ismtpd0001p1iad1.sendgrid.net (SG) with ESMTP id 9jKuol2oR6e0h9VbmeJqeg for ; Thu, 16 Jan 2020 06:58:27.512 +0000 (UTC) Date: Thu, 16 Jan 2020 06:58:27 +0000 (UTC) From: matz@ruby.or.jp Message-ID: References: Mime-Version: 1.0 X-Redmine-MailingListIntegration-Message-Ids: 72556 X-Redmine-Project: ruby-master X-Redmine-Issue-Id: 16435 X-Redmine-Issue-Author: zverok X-Redmine-Sender: matz X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-SG-EID: =?us-ascii?Q?bXEIHGfdFwsIlBTndiToCp=2Fmc2rfxRD2sZAksRKJIHW+pCMMwwS4oyXq5IIHSu?= =?us-ascii?Q?prO=2FUd=2Fsi7+4blh82on50XCIJNiEyvkULaOonE=2F?= =?us-ascii?Q?GBTPLud0a4xNwxv8B8tiGWKYp=2FIrgyvE0zegzFs?= =?us-ascii?Q?7CUJBqlUSxr+nxGU6MGDFE2lrR84gMYeLujAJTz?= =?us-ascii?Q?XkJO7apRzsYP184sVIKbrJDGXdbiNnXkSXQ=3D=3D?= To: ruby-core@ruby-lang.org X-ML-Name: ruby-core X-Mail-Count: 96894 Subject: [ruby-core:96894] [Ruby master Feature#16435] Array#to_proc X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: Ruby developers List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ruby-core-bounces@ruby-lang.org Sender: "ruby-core" Issue #16435 has been updated by matz (Yukihiro Matsumoto). Status changed from Open to Rejected Rejected. `Array#to_proc` to too generic for queries. It only makes the code more cryptic. Matz. ---------------------------------------- Feature #16435: Array#to_proc https://bugs.ruby-lang.org/issues/16435#change-83908 * Author: zverok (Victor Shepelev) * Status: Rejected * Priority: Normal * Assignee: * Target version: ---------------------------------------- The idea is obvious, but I couldn't find it discussed anywhere on tracker before. Please point me at the previous discussions if any. ```ruby class Array def to_proc proc { |v| v.dig(*self) } end end # Or, alternatively, see about alternatives at the end of proposal: class Array def to_proc proc { |v| v[*self] } end end ``` The implementation seems to provide clean and unambiguous collections indexing in Enumerators: ```ruby # Basic objects data, which could be obtained from JSON, CSV, Database... data = [ {name: 'John', department: {id: 1, title: 'Engineering'}, salary: 1000}, {name: 'Jane', department: {id: 1, title: 'Engineering'}, salary: 1200}, {name: 'Boris', department: {id: 2, title: 'Accounting'}, salary: 800}, {name: 'Alice', department: {id: 3, title: 'Management'}, salary: 1500} ] data.map(&[:name]) # => ["John", "Jane", "Boris", "Alice"] data.min_by(&[:salary]) # => {:name=>"Boris", :department=>{:id=>2, :title=>"Accounting"}, :salary=>800} pp data.group_by(&[:department, :title]) # {"Engineering"=> # [{:name=>"John", # :department=>{:id=>1, :title=>"Engineering"}, # :salary=>1000}, # {:name=>"Jane", # :department=>{:id=>1, :title=>"Engineering"}, # :salary=>1200}], # "Accounting"=> # [{:name=>"Boris", # :department=>{:id=>2, :title=>"Accounting"}, # :salary=>800}], # "Management"=> # [{:name=>"Alice", # :department=>{:id=>3, :title=>"Management"}, # :salary=>1500}]} # Works with arrays, too: data.map(&:values).map(&[0]) # => ["John", "Jane", "Boris", "Alice"] # And with mixes: data.group_by(&[:department, :title]).values.map(&[0, :name]) # => ["John", "Boris", "Alice"] ``` Naked structured data seems to be a common enough thing to make working with them easier. Some prior info: * Googling it around, I found the idea was first invented [back in 2014](https://thepugautomatic.com/2014/11/array-to-proc-for-hash-access/), and another one [in 2015](https://gist.github.com/geowy/39fde25ec2966f90a54b), not sure if it was proposed on the tracker. * Other proposals for `Array#to_proc` was: to call several methods in sequence [1](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/199820), [2](https://rails.lighthouseapp.com/projects/8994/tickets/1253-arrayto_proc), and to call method with argument [1](https://www.sanityinc.com/articles/adding-array-to-proc-to-ruby/), [2](https://bugs.ruby-lang.org/issues/10829), [3](https://www.rubydoc.info/github/estum/console_utils/Array:to_proc), to call several methods in parallel: [1](https://gist.github.com/shell/1120249) Honestly, I feel that proposed usage is the most frequently needed. Also, the readability of the version seems more or less straightforward: ```ruby # Existing shortcut, for example: data.map(&:keys) # Is equivalent to data.map { |x| x.keys } # ^^^^^ -- "just remove this part" # Proposed shortcut: data.map(&[:name]) # Is equivalent to data.map { |x| x[:name] } # ^^^^^ -- "just remove this part" ``` **`dig` or `[]` alternative implementations** It is up to discussion (if the whole idea holds water) whether `dig` should be used or just `[]`. The `dig` version is convenient for nested structures but slightly breaks "equivalency" shown above, and just `[]` version will allow this: ```ruby data.map(&:values).map(&[1..-1]) # => [[{:id=>1, :title=>"Engineering"}, 1000], [{:id=>1, :title=>"Engineering"}, 1200], [{:id=>2, :title=>"Accounting"}, 800], [{:id=>3, :title=>"Management"}, 1500]] ``` Maybe, for the sake of explainability, "just `[]`" should be preferred, with digging performed by other means. -- https://bugs.ruby-lang.org/