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=-2.6 required=3.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, FORGED_GMAIL_RCVD,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_PASS shortcircuit=no autolearn=no 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 9F3C81F463 for ; Sat, 21 Sep 2019 21:46:27 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 4DCCD120AC6; Sun, 22 Sep 2019 06:46:17 +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 91389120AC0 for ; Sun, 22 Sep 2019 06:46:14 +0900 (JST) Received: by filter0120p3las1.sendgrid.net with SMTP id filter0120p3las1-2980-5D869A23-B 2019-09-21 21:46:11.279101337 +0000 UTC m=+117976.187209649 Received: from herokuapp.com (unknown [3.85.105.179]) by ismtpd0024p1iad2.sendgrid.net (SG) with ESMTP id cm3O1pPwSTGP-LtwXkeYIg for ; Sat, 21 Sep 2019 21:46:11.081 +0000 (UTC) Date: Sat, 21 Sep 2019 21:46:11 +0000 (UTC) From: sammomichael@gmail.com Message-ID: References: Mime-Version: 1.0 X-Redmine-MailingListIntegration-Message-Ids: 70581 X-Redmine-Project: ruby-trunk X-Redmine-Issue-Id: 16147 X-Redmine-Issue-Author: sammomichael X-Redmine-Sender: sammomichael 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?slqsTT=2F+PuUcADLY9nggyMdJj+djGZd32YYUR+KNBmZHWy3l7yVJYMqwX7IubN?= =?us-ascii?Q?kgTv6QSFWYtD8T5ipySrxo7mhSniZQ9YCSjV2es?= =?us-ascii?Q?te9SYTC7kj3TwnV1jx0By5OleF72czjoTZTqTCV?= =?us-ascii?Q?6VWWFdad0LZEhwM+RNq2h3kmzAgZofIb4jH=2Fzpn?= =?us-ascii?Q?JaSqqHmz4HrJQoqEHuTjqmM5nxuN3ij0IAA=3D=3D?= To: ruby-core@ruby-lang.org X-ML-Name: ruby-core X-Mail-Count: 95026 Subject: [ruby-core:95026] [Ruby master Feature#16147] List Comprehensions in Ruby 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 #16147 has been updated by sammomichael (Samuel Michael). In reiteration of my main points, Ruby is a dynamic multi-paradigm language which should when possible embrace a variety of modes to achieve the same result. SO what would be the benefits of list comprehension in Ruby and what would it look like? 1. Creating an array with only [] square brackets is fun and makes intuitive sense for beginners 2. "For .. in .." syntax is succinct, flexible, and has a good spoken rhythm/easy to verbalize 3. Easier for users of other languages to assimilate into Ruby as they don't need to know all our enumerable library right away. Ruby already has functioning list comprehension syntax but it could be optimized: [for x in 1..10 do x**2 if x%2==0 end] # this is Ruby but we can't capture the value [for x in 1..10; x**2 if x.even? end] # since 2.7 Ruby it would also be better if it called Filter_Map under the hood instead of each # proposal to use some syntax to use a splat or additional indicator to allow a smoother shorthand for list comprehensions [for x in 1..10 do x**2 if x.even? end] #=> 1..10 (normal Ruby) # below we propose a syntax in which we splat the for loop to return the stored result not the caller [*for x in 1..10 do x**2 if x.even? end] #=> [4, 16, 36, 64, 100] # under the hood this could be syntactic sugar for (1..10).filter_map{@1**2 if @1.even?} #=> [4, 16, 36, 64, 100] # the key differences to notice. although there are less keystrokes with filter_map, you had to know the method name, and the exact arrangement of parentheses and curly braces, and whether to use a block or numbered parameter. If you decided to use pre-2.7 ruby you would have said: (1..10).filter_map{|x|x**2 if x.even?} vs with proposed list syntax: [*for x in 1..10; x**2 if x.even? end] # I think both could and should be standard ruby syntax of achieving the same result of quickly generating a filter mapped array of the given elements. ---------------------------------------- Feature #16147: List Comprehensions in Ruby https://bugs.ruby-lang.org/issues/16147#change-81654 * Author: sammomichael (Samuel Michael) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- ## List comprehensions are present in many languages and programmers are quite fond of their simplicity and power. Add to that the fact that Ruby has a for...in loop that is rarely used but could possibly be repurposed. ### Currently we can already do a hack like this to make Ruby support list comprehension syntax: ``` ruby S = [for x in 0...9 do $* << x*2 if x.even? end, $*][1] # [0, 4, 8, 12, 16] ``` Still, it would be far nicer if the for...in loop would return the desired array automatically, this is one way to approach that taking advantage of lambda bracket invocation syntax: ``` ruby c = -> x do $*.clear if x['if'] && x[0] != 'f' . y = x[0...x.index('for')] x = x[x.index('for')..-1] (x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}") x.insert(x.length, "end; $*") eval(x) $*) elsif x['if'] && x[0] == 'f' (x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << x") x.insert(x.length, "end; $*") eval(x) $*) elsif !x['if'] && x[0] != 'f' y = x[0...x.index('for')] x = x[x.index('for')..-1] (x.insert(x.index(x.split[3]) + x.split[3].length, " do $* << #{y}") x.insert(x.length, "end; $*") eval(x) $*) else eval(x.split[3]).to_a end end ``` so basically we are converting a string to proper ruby syntax for loop then we can use python syntax in a string to do: ``` ruby c['for x in 1..10'] c['for x in 1..10 if x.even?'] c['x**2 for x in 1..10 if x.even?'] c['x**2 for x in 1..10'] # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # [2, 4, 6, 8, 10] # [4, 16, 36, 64, 100] # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] ``` -- https://bugs.ruby-lang.org/