Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:61021 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 30366 invoked from network); 28 Jun 2012 11:00:30 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 28 Jun 2012 11:00:30 -0000 Received: from [127.0.0.1] ([127.0.0.1:25080]) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ECSTREAM id E3/A9-08168-E493CEF4 for ; Thu, 28 Jun 2012 07:00:30 -0400 Authentication-Results: pb1.pair.com smtp.mail=nikita.ppv@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=nikita.ppv@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.217.170 as permitted sender) X-PHP-List-Original-Sender: nikita.ppv@gmail.com X-Host-Fingerprint: 209.85.217.170 mail-lb0-f170.google.com Received: from [209.85.217.170] ([209.85.217.170:56262] helo=mail-lb0-f170.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id B0/99-08168-B963CEF4 for ; Thu, 28 Jun 2012 06:48:59 -0400 Received: by lbgc1 with SMTP id c1so3319144lbg.29 for ; Thu, 28 Jun 2012 03:48:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=53q9rI2WRfcWIhiFHdxBO+sTndMzzoKZ5M/pcMIkIIU=; b=Ii7iDuez3e5zprx197vU2X/lZYdeYdzuzZYIsbI45DY0XNXtbeKsI6lx97YzU6hoJl df+gLaEF1JSnkp7OUxVV3/JzgECqGRhA4gD7avIrFpt5F2YY0XY3dOQkZOWZJvq+RAk1 qoS4PnIRtASvrUaTGfAQ8HqklSropgYUV1z5y0Kd028CpPE5Z8BjjLLtXdwWDgTyO0PJ 40YYqE8N9Bud3G8kaScP4e7R1hfDPauDLXJlPrObmaRn5bihnSjIieOLAZjnFvZfp78Y 78tetrfI6AxFVSDNLZeqY9xvrBw/9R56cOsGdRtQlyTELhZJsVdn+BiZq67TerXpfypN MSMA== MIME-Version: 1.0 Received: by 10.152.144.168 with SMTP id sn8mr1647613lab.1.1340880536229; Thu, 28 Jun 2012 03:48:56 -0700 (PDT) Received: by 10.152.114.70 with HTTP; Thu, 28 Jun 2012 03:48:56 -0700 (PDT) Date: Thu, 28 Jun 2012 12:48:56 +0200 Message-ID: To: PHP internals Content-Type: text/plain; charset=ISO-8859-1 Subject: List comprehensions and generator expressions for PHP From: nikita.ppv@gmail.com (Nikita Popov) Hi internals! Python and several other languages include support for list comprehensions and generator expressions and I'd like to see something similar in PHP too. I created a hacky proof of concept implementation here: https://github.com/nikic/php-src/tree/addListComprehensions. It's really dirty, but it implements both features in about ~150 lines of code. Currently I'm using the following syntax: $firstNames = [foreach ($users as $user) yield $user->firstName]; This code is roughly equivalent to writing: $firstNames = []; foreach ($users as $user) { $firstNames[] = $user->firstName; } You may notice that this particular list comprehension provides the same functionality as array_column(), just in a little more generalized way. E.g. you could use all of the following without having special functions for them all: $firstNames = [foreach ($users as $user) yield $user->firstName]; $firstNames = [foreach ($users as $user) yield $user->getFirstName()]; $firstNames = [foreach ($users as $user) yield $user['firstName']]; It's also possible to explicitly specify a key: $firstNames = [foreach ($users as $user) yield $user->id => $user->firstName]; It is also possible to filter elements using list comprehensions: $underageUsers = [foreach ($users as $user) if ($user->age < 18) yield $user]; // or just the names $underageUserNames = [foreach ($users as $user) if ($user->age < 18) yield $user->firstName]; It is also possible to nest multiple foreach loops: $aList = ['A', 'B']; $bList = [1, 2]; $combinations = [foreach ($aList as $a) foreach ($bList as $b) yield [$a, $b]]; // gives: [ ['A', 1], ['A', 2], ['B', 1], ['B', 2] ] All the above are list comprehensions (or in PHP rather array comprehensions), i.e. they create an array as the result. If this is not needed it is also possible to compute the values lazily using generator expressions, which use () instead of []. $firstNames = (foreach ($users as $user) yield $user->firstName); In this case $firstNames will no longer be an array of first names, but instead will be a generator producing first names. This is handy if you only need to iterate the resulting "list" only once as it saves you holding the whole list in memory. Also it allows you to work with infinite lists easily: function *naturalNumbers() { for ($i = 0; ; ++$i) { yield $i; } } // all natural numbers $numbers = naturalNumbers(); // only the odd ones $oddNumbers = (foreach ($numbers as $n) if ($n % 2) yield $n); // ... (At this point I wonder whether one should include support for for-loops in list comprehensions. So the naturalNumbers() function could be replaced with (for ($i = 0;; ++$i) yield $i), etc) So, what do you think? Do we want something like this in PHP? Nikita