0,4
рейтинг
14 июля 2014 в 12:01

Разработка → 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 относительно моей версии). Бенчмарки в процессе, напишу в следующий раз.
Александр Прохоров @Athari
карма
105,0
рейтинг 0,4
Программист C#
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (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# на замену?
                    • +1
                      Да.
          • +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
      Если приглядеться, в коде ещё кое-что можно усмотреть, но лучше так не делать.

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