From: daniel@...42.com Date: 2019-12-30T02:40:49+00:00 Subject: [ruby-core:96588] [Ruby master Feature#16435] Array#to_proc Issue #16435 has been updated by Dan0042 (Daniel DeLorme). If I understand correctly, you are saying that of these: ```ruby list.select(&:condition?) list.select{.condition?} list.select{_1.condition?} list.select{|x|x.condition?} ``` you consider that the first one provides some kind of clarity of understanding that you don't find in the oher three and that leads to better design? If that's the case then I'm afraid you've lost me. Apart from niceness of syntax, these four lines are conceptually identical to me. I agree with your example that `select { |o| check some condition (o) }` would be better structured as `select(&:condition?)` ... OR the equivalent (just a bit uglier) `select{_1.condition?}` I also have an issue with the way you repurpose array literals to play the role of hash/array accessors. That's a hack. It relies on the coincidence that they both use square brackets. What do you expect that `max_by(&ary)` would mean? If there was such a thing as `Array#to_proc` I would expect it to act as if the array was a call-able object. I imagine it would be similar to `Hash#to_proc`, where `hash[key] == hash.to_proc[key]`. Now that would be a semantically meaningful `Array#to_proc`. ---------------------------------------- Feature #16435: Array#to_proc https://bugs.ruby-lang.org/issues/16435#change-83555 * Author: zverok (Victor Shepelev) * Status: Open * 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/ Unsubscribe: