YaLinqo (LINQ to Objects для PHP) — версия 2.0

    Что-что?

    LINQ — это штука, которая позволяет писать запросы, чем-то похожие на SQL, прямо в коде. LINQ to Objects, собственно, позволяет писать запросы к объектам, массивам и всему тому, чем вы оперируете в коде.

    Это ещё зачем?

    Если у вас есть база, то у вас есть любимый ORM (или любимый голый SQL — кому как по вкусу). Но иногда объекты приходят из веб-сервисов, из файлов, да и вообще тьма тьмущая объектов может требовать нетривиальной обработки: преобразование, фильтрация, сортировка, группировка, агрегация… Применить бы привычный ORM или SQL — но базы-то нет. Тут на помощь приходит LINQ to Objects, в данном случае YaLinqo.

    Что умеет?

    • Самый полный порт .NET LINQ на PHP, со многими дополнительными методами. Всего реализовано более 70 методов.
    • Ленивые вычисления, текст исключений и многое другое, как в оригинальном LINQ.
    • Детальная документация PHPDoc к каждому методу. Текст статей адаптирован из MSDN.
    • 100% покрытие юнит-тестами.
    • Коллбэки можно задавать замыканиями, «указателями на функцию» в виде строк и массивов, строковыми «лямбдами» с поддержкой нескольких синтаксисов.
    • Ключам уделяется столько же внимания, сколько значениям: преобразования можно применять и к тем, и к другим; большинство коллбэков принимает на вход и то, и другое; ключи по возможности не теряются при преобразованиях.
    • Минимальное изобретение велосипедов: для итерации используются Iterator, IteratorAggregate и др. (и их можно использовать наравне с Enumerable); исключения по возможности используются родные похапэшные и т.п.
    • Поддерживается Composer, есть пакет на Packagist.
    • Никаких внешних зависимостей.

    Что случилось?

    Прошёл год, как вышел PHP 5.5 со всякими вкусностями типа генераторов и исправленных итераторов. Так как на моей совести самый полноценный порт LINQ на PHP, то я решил, что настало время его обновить и воспользоваться новыми фичами языка.

    Что нового?

    Скорость новая. Выкинуты тонны кода (порядка 800 строк под подсчётам Git): не стало костылей вроде Enumerator для генерации Iterator'ов; не стало бесполезных коллекций, по сути единственным преимуществом которых было хранение объектов в ключах; не стало call_user_func… И самое главное — не стало кучи маловменяемого кода для генерации итераторов, который невозможно понять. Остался foreach и yield. Всё это в сумме дало нехилый прирост в скорости.

    Вы не представляете, с каким удовольствием я заменял этого монстра:

    return new Enumerable(function () use ($self, $inner, $outerKeySelector, $innerKeySelector, $resultSelectorValue, $resultSelectorKey)
    {
        /** @var $self Enumerable */
        /** @var $inner Enumerable */
        /** @var $arrIn array */
        $itOut = $self->getIterator();
        $itOut->rewind();
        $lookup = $inner->toLookup($innerKeySelector);
        $arrIn = null;
        $posIn = 0;
        $key = null;
    
        return new Enumerator(function ($yield) use ($itOut, $lookup, &$arrIn, &$posIn, &$key, $outerKeySelector, $resultSelectorValue, $resultSelectorKey)
        {
            /** @var $itOut \Iterator */
            /** @var $lookup \YaLinqo\collections\Lookup */
            while ($arrIn === null || $posIn >= count($arrIn)) {
                if ($arrIn !== null)
                    $itOut->next();
                if (!$itOut->valid())
                    return false;
                $key = call_user_func($outerKeySelector, $itOut->current(), $itOut->key());
                $arrIn = $lookup[$key];
                $posIn = 0;
            }
            $args = array($itOut->current(), $arrIn[$posIn], $key);
            $yield(call_user_func_array($resultSelectorValue, $args), call_user_func_array($resultSelectorKey, $args));
            $posIn++;
            return true;
        });
    });
    

    на лаконичное:

    return new Enumerable(function () use ($inner, $outerKeySelector, $innerKeySelector, $resultSelectorValue, $resultSelectorKey) {
        $lookup = $inner->toLookup($innerKeySelector);
        foreach ($this as $ok => $ov) {
            $key = $outerKeySelector($ov, $ok);
            if (isset($lookup[$key]))
                foreach ($lookup[$key] as $iv)
                    yield $resultSelectorKey($ov, $iv, $key) => $resultSelectorValue($ov, $iv, $key);
        }
    });
    

    Кроме этого, я наконец-то добавил человеческие теги с версиями в репозиторий и описал алиасы веток в composer.json, поэтому работа с Composer теперь должна вызывать меньше боли.

    Так что это такое, в конец-то концов?

    Допустим, у вас есть массивы:

    $products = array(
        array('name' => 'Keyboard',    'catId' => 'hw', 'quantity' =>  10, 'id' => 1),
        array('name' => 'Mouse',       'catId' => 'hw', 'quantity' =>  20, 'id' => 2),
        array('name' => 'Monitor',     'catId' => 'hw', 'quantity' =>   0, 'id' => 3),
        array('name' => 'Joystick',    'catId' => 'hw', 'quantity' =>  15, 'id' => 4),
        array('name' => 'CPU',         'catId' => 'hw', 'quantity' =>  15, 'id' => 5),
        array('name' => 'Motherboard', 'catId' => 'hw', 'quantity' =>  11, 'id' => 6),
        array('name' => 'Windows',     'catId' => 'os', 'quantity' => 666, 'id' => 7),
        array('name' => 'Linux',       'catId' => 'os', 'quantity' => 666, 'id' => 8),
        array('name' => 'Mac',         'catId' => 'os', 'quantity' => 666, 'id' => 9),
    );
    $categories = array(
        array('name' => 'Hardware',          'id' => 'hw'),
        array('name' => 'Operating systems', 'id' => 'os'),
    );
    

    Допустим, вам нужно разместить продукты с ненулевым количеством в соответствующие отсортированные по имени категории, и внутри категорий отсортировать продукты сначала по убыванию количества, потом по имени. Сейчас вы начинаете строить в уме трижды вложенные циклы, вызовы функций для массивов, пытаетесь вспомнить, какой префикс у подходящей функции сортировки… Вместо всего этого можно написать:

    $result = from($categories)
        ->orderBy('$cat ==> $cat["name"]')
        ->groupJoin(
            from($products)
                ->where('$prod ==> $prod["quantity"] > 0')
                ->orderByDescending('$prod ==> $prod["quantity"]')
                ->thenBy('$prod ==> $prod["name"]'),
            '$cat ==> $cat["id"]', '$prod ==> $prod["catId"]',
            '($cat, $prods) ==> [
                "name" => $cat["name"],
                "products" => $prods
            ]'
        );
    

    Если бы создатели PHP не были упёртыми ослами и не отказались от пулл-реквеста с лямбдами, можно было бы написать даже так:

    $result = from($categories)
        ->orderBy($cat ==> $cat['name'])
        ->groupJoin(
            from($products)
                ->where($prod ==> $prod['quantity'] > 0)
                ->orderByDescending($prod ==> $prod['quantity'])
                ->thenBy($prod ==> $prod['name']),
            $cat ==> $cat['id'], $prod ==> $prod['catId'],
            ($cat, $prods) ==> [
                'name' => $cat['name'],
                'products' => $prods,
            ]
        );
    

    Так или иначе, на выходе мы получим:

    Array (
        [hw] => Array (
            [name] => Hardware
            [products] => Array (
                [0] => Array ( [name] => Mouse       [catId] => hw [quantity] =>  20 [id] => 2 )
                [1] => Array ( [name] => CPU         [catId] => hw [quantity] =>  15 [id] => 5 )
                [2] => Array ( [name] => Joystick    [catId] => hw [quantity] =>  15 [id] => 4 )
                [3] => Array ( [name] => Motherboard [catId] => hw [quantity] =>  11 [id] => 6 )
                [4] => Array ( [name] => Keyboard    [catId] => hw [quantity] =>  10 [id] => 1 )
            )
        )
        [os] => Array (
            [name] => Operating systems
            [products] => Array (
                [0] => Array ( [name] => Linux       [catId] => os [quantity] => 666 [id] => 8 )
                [1] => Array ( [name] => Mac         [catId] => os [quantity] => 666 [id] => 9 )
                [2] => Array ( [name] => Windows     [catId] => os [quantity] => 666 [id] => 7 )
            )
        )
    )
    

    Для эстетов и оптимизаторов есть возможность использовать анонимные функции, а не «строковые лямбды». Вместо '$prod ==> $prod["quantity"] > 0' можете писать function ($prod) { return $prod['quantity'] > 0; }. Для диких обфускаторов есть возможность использовать имена аргументов по умолчанию (v — значение, k — ключ и т.п.), то есть можно писать просто '$v["quantity"] > 0' (для сложных вложеных запросов не рекомендуется).

    А где LINQ to Database?

    Да, вообще-то в мире .NET запросы LINQ используются и в ORM (кто-то скажет, что это вообще основное назначение), но конкретно эта фича в библиотеке отсутствует, потому что любая попытка её реализовать выльется в тонну костылей, тормозов и прочих неприглядных вещей из-за отсутствия поддержки на уровне языка (разбора выражений, в частности). LINQ to Objects-то не обошёлся без костылей в виде «строковых лямбд», а тут полноценный транслятор из PHP в SQL с полным разбором и тоннами оптимизаций понадобится — закат солнца вручную.

    Давай!


    P.S. Старая версия поддерживает PHP 5.3. Функционально не уступает, но несколько тормознее (итераторы-с).

    P.P.S. Наконец-то появился вменяемый конкурент (Ginq). В нём тонны SPL, Symfony и прочей арихитектуры, ноль комментариев, много тормозов (оверхед от x2 до x50 относительно моей версии). Бенчмарки в процессе, напишу в следующий раз.
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 45
    • +1
      LINQ в C# (благодаря компиляции и IDE) даёт возможность при вводе запросов выводить типы.
      • +1
        То есть у вас основная претензия — это что автодополнение кода не работает?..
        • +2
          С чего вы взяли? Это — информация к размышлению и возможное направление развития языка и его инструментов.
          • +1
            По-моему, вы немного не по адресу. В PHP утиная типизация, какого вывода типов вы от него хотите? А делать вывод типов как в примере выше на уровне IDE — это очень сложное и неблагодарное занятие. Я не знаю сред разработки для динамически типизированных языков, которые умеют подобное вытворять (ну, разве что в частных случаях).
            • 0
              В PHP утиная типизация
              С каких пор?
              • +3
                Вы часто видите типы у аргументов функций? А у результатов функций и переменных? :) Или, может, скалярные типы в type hinting уже поддерживаются? Или вообще, в стандартных функциях «mixed» уже не упоминается?

                PHP, конечно, пытается мимикрировать под джаву, но — слава богам! — пока не настолько активно.
                • +1
                  Действительно, каюсь. Понедельник — день тяжелый.
            • 0
              Вы путаете утиную и динамическую типизацию.
              • +1
                Утиная типизация — вид динамической, так что автор ничего не путает.

                <?php
                class Duck {
                    function quack() { echo "Quack", PHP_EOL; }
                    function fly() { echo "Flap, Flap", PHP_EOL; }
                }
                 
                class Person {
                    function quack() { echo "I try to imitate a duck quack", PHP_EOL; }
                    function fly() { echo "I take an aeroplane", PHP_EOL; }
                }
                 
                function in_the_forest($object) {
                    $object->quack();
                    $object->fly();
                }
                 
                in_the_forest(new Duck);
                in_the_forest(new Person);
                


                Quack
                Flap, Flap
                I try to imitate a duck quack
                I take an aeroplane
                
      • 0
        Это умеет IDE, не вижу особо проблем с тем, что бы написать простенький плагин для какого phpstorm с добавлением ресолва типов в замыканиях и для автокомплита.
        • 0
          Вы уверены, что плагин будет простеньким? А то уже вечность висит баг WI-3477 про недоступность PHP в списке «внедряемых языков» (фича, которая позволяет определять и анализировать SQL внутри строк, например).
          • 0
            Ну я лично против php внутри строк, тем более что этот тикет никак не повлияет на вашу реализацию. у вас все же синтаксис замыканий не являтся валидным для php. Все относительно конечно, но не вижу особых проблем. А тот тикет — он не нужен никому.
            • 0
              Эти строки можно писать по-разному, один из синтаксисов валиден. Можно и добавить альтернативу, например, заменить ==> на /**/. От реализации этого тикета анализа кода в строке не появится, но хоть будет нормальная подсветка и проверка синтаксиса.

              PHP в строках — зло, но это далеко не единственная библиотека, которая этим грешит. Какая-нибудь аннотация типа «этот аргумент — код» определённо не помешала бы.
    • 0
      Выглядит классно, но хотелось бы пару бенчмарков. Сколько времени исполняется ваш пример на тестовом массиве, скажем, из пары тысяч элементов?
      • 0
        Вы можете написать аналог на голом PHP для сравнения?

        В моих бенчмарках с относительно простыми запросами оверхед болтается между 20% и 200%, в основном 50%–100% (во сравнению с реализацией на циклах). Чем меньше действий происходит в «теле», тем больше оверхед в процентном отношении (на абсолютно голом цикле можно получить 500%). От использования функций на массивах с колбэками скорость тоже заметно просаживается, к слову. Сколько потеряет конкретное приложение — надо смотреть по приложению.

        Если память не изменяет, LINQ в .NET тоже просаживает скорость. Какое-то время назад обещали, что заоптимизировали, но не проверял.
        • +1
          Ну оверхэд за счет вызова функций и прочего естественно будет, тут уж ничего не поделать. Можно попробовать написать аналог чисто на map/reduce/filter/usort что бы было чеснее. Так же стоит включить в бенчмарки статистику по потреблению памяти, просто из любопытства.
    • +2
      Сахар сахаром, но хранить куски кода в строках — брррррр. Ничего не имею против самой либы, но пользоваться ей (если бы пришлось) я бы стал только примерно так:
      <?php
      $result = from($categories)
          ->orderBy(function($cat){return $cat["name"];})
          ->groupJoin(
              from($products)
                  ->where(function($prod){return $prod["quantity"] > 0;})
                  ->orderByDescending(function($prod){return $prod["quantity"];})
                  ->thenBy(function($prod){return $prod["name"];}),
              function($cat){return $cat["id"];},
              function($prod){return $prod["catId"];},
              function($cat, $prods){return [
                  "name"     => $cat["name"],
                  "products" => $prods,
              ];}
          );
      

      Громоздко, сложно к восприятию. Но всяко, имхо, лучше строк.
      • +1
        P.S. Если и так часть кода — это простые function($a) { return $a['fieldName']; } то почему бы не заменить на:
        <?php
        $result = from($categories)
            ->orderBy('name')
            ->groupJoin(
                from($products)
                    ->where('quantity', '_ > 0') // это уже фантазии на тему
                    ->orderByDescending('quantity')
                    ->thenBy('name'),
                ['id', 'catId'],
                function($cat, $prods){return [
                    "name"     => $cat["name"],
                    "products" => $prods,
                ];}
            );
        

        • 0
          По сути такимо образом пытались видимо обойти то ограничения, что в PHP нету удобного синтаксиса для лямбд. Да и ваш вариант сложнее воспринимать.
          • 0
            Первый вариант да, он является полным аналогом варианта из поста (если я правильно его понял). Второй же подход мне видится гораздо симпатичнее.
            Для сравнения
                ->orderByDescending($prod ==> $prod['quantity'])
                ->thenBy($prod ==> $prod['name']),
            

            и
                ->orderByDescending('quantity')
                ->thenBy('name'),
            


            Уж, думаю, библиотека может выполнить что-то вида
            if (is_string($v)) {
                $res = isset($dict[$v]) ? $dict[$v] : null;
            }
            elseif (is_callable($v)) {
                $res = $v($dict);
            }
            else ...
            
        • 0
          Вы оптимизировали синтаксис под частный случай. :) А если в where мне нужно условие и для значения, и для ключа (массивы в PHP содержат и то, и другое)? А если мне нужно отсортировать по синусу количества? А если ключи массива для соединения вложенные, и вообще это не ключи масства, а свойства объекта или результаты вызова функций? А как мне передать ссылку на именованную функцию (подсказка: в PHP указатели на функции трёх типов: строки для функций, массивы из пары объект-строка для методов, массивы из пары строка-строка для статических методов)? И так далее.

          В Ginq есть синтаксис для получения полей из Symfony (и нет строковых лямбд), но эта штука просто космически тормозная — оверхед за 1000% и дальше. И эта штука удобна в join'ах и сортировках, но совершенно бесполезна в select и прочих методах.

          В принципе, отдельный синтаксис лямбд для получения полей не лишён смысла, но это надо хорошо продумать, с бухты-барахты это не сделаешь. И уж точно нет смысла менять аргументы у функций, потому что от всех вариантов перегрузок тогда можно будет убиться (и сейчас-то непросто, со всеми этими ключами).
          • 0
            Я не знаком с LINQ, оценивал по вами же приведенным примерам :)

            >> А если в where мне нужно условие и для значения, и для ключа
            where(function($k, $v) {return $v['quantity'] > 0 && ($k%2 == 0);}) 

            >>А если мне нужно отсортировать по синусу количества?
            orderByDescending('quantity', 'sin(_)')

            >>и вообще это… свойства объекта…
            __get, ArrayAccess,…

            >>А как мне передать ссылку на именованную функцию
            use(...)? Или не совсем понял о чем речь.

            Я к чему это все. Всякий раз сталкиваясь с «yet another LINQ port», не понимаю, зачем настолько досконально пытаться перенести на тот же PHP то, что целиком и полностью завязано на возможностях синтаксиса C#. Почему не продумать альтернативу при похожем подходе с цепочками вызовом?
    • –2
      Сейчас вы начинаете строить в уме трижды вложенные циклы, вызовы функций для массивов

      1. А при вызове функций библиотеки сколько вложенных циклов будет? К примеру, в вашем примере какая сложность алгоритма получается?

      2. Ведь данные хранятся в БД, соотвественно нужные данные в нужном формате можно выбрать SQL запросом, что убдет явно быстрее чем их обработка на PHP.

      3. Интересно было бы посмотреть сравнение быстродействия и используемой памяти:
      — Использование SQL запроса;
      — Обратботка сущесвующих массивов с помощью YaLinqo (хотя сюда нужно суммировать и выборку данных из БД, потому что вряд ли вы данные храниет в массивах);
      — То же самое что и предыдущий вариант, только вместо библиотеки — реализация нанативном пхп под определенную задачу.
      • 0
        А при вызове функций библиотеки сколько вложенных циклов будет? К примеру, в вашем примере какая сложность алгоритма получается?

        Математическая сложность алгоритма не меняется. Меняется «логическая» сложность алгоритма. Например, цепочка select-where-selectMany представляется линейной цепочкой вызовов, и человек воспринимает это как простую последовательность трёх операций: преобразовать, отфильтровать, преобразовать со слиянием. Если же разворачивать цепочку в код, то будут вложенные for-if-for-for, которые сильно напрягут мозг и заставят анализировать кучу мусора. join за собой скрывает for-if-for, некоторые больше, некоторые меньше. Последовательные операции в разы проще воспринимать, чем вложенные. Сортировка orderBy-thenBy — проще, чем usort и колбэк с функцией сравнения (кода в три раза больше, распознавать порядок ещё сложнее).

        Ведь данные хранятся в БД, соотвественно нужные данные в нужном формате можно выбрать SQL запросом, что убдет явно быстрее чем их обработка на PHP.

        Не все данные хранятся в БД. Вы б второй абзац прочитали что ли.

        По поводу быстродействия см. комментарии выше.
        • +4
          По поводу «логической» сложности полностью согласен. А по поводу математической — нет. Ведь использование дополнительной функции, библиотеки, фреймворка — явно увеличивает сложность. Только что я не много потыкал под xhprof. Вот код с использованием либы, а вот нативный. И результаты:
          Нативный:

          С либой:

          Видно, что с использованием либы — памяти раз в 5 больше и скорость выполнения — раз в 8 и количество вызываемых функциий — раз в 10. Если решать задачу с использованием SQL запроса — то еще быстрее.
          Об этом я и спрашивал.

          Я не спорю, что нативный код не всегда хорош (не учитывая хайлоад приложения), и подход который предлагаете Вы- явно удобнее и логически приятнее читать, особенно если бы не было лямбда функций в строках, но использование дополнительных библиотек — это всегда жертвование ресурсов, и здесь важно знать, чем ты жертвуешь и в каком количестве.
          • +1
            Идеальный комментарий, который я искал, открывая топик =)
          • 0
            Хм. Расход памяти какой-то конский. Там не должно выделяться столько. Надо глянуть.

            А по поводу математической — нет.

            Мера О та же самая. Коэффициенты и константы, разумеется, отличаются.

            а вот нативный

            1. Вы неправильно отсортировали категории: отсортировали по и так возрастающему ключу, хотя требовалось по имени. То есть не отсортировали вообще.
            2. Вы неправильно отсортировали продукты: отсортировали только по количеству, хотя надо было по двум полям, в том числе по имени.

            Собственно, к вопросу о наглядности кода. :)

            Если решать задачу с использованием SQL запроса — то еще быстрее.

            Если у вас есть база с гигабайтами данных, то использование этой библиотеки — ошибка по определению. Эта библиотека предназначена для случаев, когда SQL нет. Вот вы от веб-сервиса получили сотню записей — вы будете запихивать их в базу, чтобы применить SQL?

            Кроме того, что сравнение с SQL идейно некорректно (вы ещё с C++ сравните), оно неадекватно и по другой причине: в реальном коде гораздо больше шансы увидеть толстые ORMы, а не голый SQL. На ORMы все плюются, но пользуются. Здесь примерно та же история.

            не учитывая хайлоад приложения

            PHP и хайлоад в одном предложении — признак недальновидности.
            • 0
              Да, точно. Времени не было толком, что бы сделать все.
              Вот с сортировками правильными (хотя может и тут ошибки есть):



              Разница с предыдущим вариантом использования нативного — не велика.

              Мера О та же самая. Коэффициенты и константы, разумеется, отличаются.

              Я почемуто уверен, что вложенность будет выше, соотвестно степень N будет возростать.

              Для решения на нативном коде — потребуется больше времени, хотя есть такая мудрость — «Нету смысла подключать дополнительный пакет компонентов в 100500 строк, чтобы твой исходник уменьшился на 10 строк».

              P.S. Я не осуждаю и не навязываю холивар. Я уважаю вашу работу. Я пытаюсь разобраться в этом — «использование дополнительных библиотек — это всегда жертвование ресурсов, и здесь важно знать, чем ты жертвуешь и в каком количестве»

              • 0
                Вот с сортировками правильными

                Теперь сортировка по коду первого символа в нижнем регистре. о_О Почему не strcmp?

                Ладно, не суть важно. Погонял у себя (правда без xhprof) — соотношение примерно то же, только раз в пять быстрее.

                1. На строковых лямбдах можно сэкономить (эвал — он и в Африке эвал).
                2. Погонял туда-сюда числа продуктов и категорий — соотношение скорости между голым PHP и YaLinqo сохраняется, так что остаюсь убеждённым про тот же порядок сложности.
                3. Вызовы функций в PHP таки космически дорогие…
                • 0
                  2. Погонял туда-сюда числа продуктов и категорий — соотношение скорости между голым PHP и YaLinqo сохраняется, так что остаюсь убеждённым про тот же порядок сложности.

                  Очень круто, когда есть график, когда по X — размер данных, по Y — время :) Особенно если на графике показано несколько реализаций решения.
                  • –1
                    Не спорю, круто, но мне лень. :) Если уж на то пошло, то я и на PHP-то последнее время не программирую. Так, решил обновить библиотеку, чтобы не протухла. Всё-таки мой единственный опенсорсный проект, который живыми людьми используется (если packagist не врёт).
                    • 0
                      >> Если уж на то пошло, то я и на PHP-то последнее время не программирую
                      C# на замену?
            • +4
              PHP и хайлоад в одном предложении — признак недальновидности.

              Тоже спорно. Это уже как стереотип — ПХП плохой, подходит только для бюджетных не больших проектов.
              С правильным подходом и хорошей архитектурой приложения — мощный инструмент, с помощью которого вполне можно и хайлоад приложения разрабатывать.
              Просто слово «хайлоад» — резиновое. Нужно более конкретно говорить :)

              P.S. На пхп писать «говнокод» в разы легче и порог вхождения низкий, в отличии от других языков, по этому так и бывает, что когда видишь уже готовый проект — начинается паника :)
    • 0
      Прошу прощения, промахнулся. Переместил комментарий в правильную ветку.
    • 0
      А что там за проблема с лямбдами? Давно уже стараюсь на PHP не писать, так что просто не в курсе. Строки с кодом выглядят не приятно.
      • +4
        Был предложен патч который позволял избавиться от «function () {… } » и использовать более короткую запись, но мейнтейнеры посчитали что это слишком сложно и потому не нужно (тоже самое было и с полноценными геттерами и сеттерами аналогами из C#, там вообще было две реализации предложено). Вообще иногда кажется что они специально развивают язык в том направлении чтобы им могли пользоваться абсолютные идиоты, кладя болт на реальные проблемы (я всё удивляюсь как генераторы пропихнули)…
        • 0
          C# для меня сейчас вообще единственная причина того, что у меня win — основная ОС. Да, да, есть Mono, но VS+R# слишком уж сладкая парочка.
        • 0
          «сложным» не в контексте «разработчики не разберутся как это использовать» а сложно поддерживать. Вообще сложность состоит в убогом парсере, от которого уже который год хотят избавиться (этот же чувак ответственен за то что в PHP есть генераторы), но пока есть другие приоритеты видимо. Вот они управление памятью перепилили, глядишь и парсером займутся.
          • 0
            Т.е. если от убого парсера всё-таки избавятся можно надеяться и на нормальные лямбы и на геттеры? Хорошо бы…
            • 0
              Вроде как решили пока не торопиться и оставить старый добрый single-pass парсер с кастылями и хаками. Во всяком случае после 2012-ого я ничего нового по этой теме не слышал.
          • 0
            сложность состоит в убогом парсере

            Что касается парсера, то меня убивают «фичи»:

            1. Ура! Теперь можно писать (new Foo)->baz()!
            2. Ура! Теперь можно писать foo()['baz']!

            В каждой новой версии одно и то же…
            • 0
              Изза убогости парсера такие вещи не так то легко сделать. Вроде как только недавно добавили пулреквест реализующий почти все (а то и все) варианты разыменования.
    • +1
      грусть
      картинка не грузится: habrastorage.org/files/59f/10c/bc0/59f10cbc05744da396d4d2b8029dc30b.png
      • 0
        Если приглядеться, в коде ещё кое-что можно усмотреть, но лучше так не делать.

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.