Поддержка замыканий в C/C++/Objective-C в Snow Leopard

    Угадайте, что это такое:

    testblock = ^(char *s) { printf("String is %s\n", s); };
    testblock("TEST!");

    * This source code was highlighted with Source Code Highlighter.

    Скоро подобные конструкции будут все чаще встречаться в приложениях для Mac OS и, возможно, iPhone OS.

    Еще в конце лета 2008 года Apple объявила, что работает над расширениями к C/C++/Obj-C под условным названием «блоки» (Blocks), которые представляют из себя ни что иное, как замыкания (closure).


    Зачем все это?


    Использование замыканий зачастую позволяет сделать код чище и понятнее, но это не единственная причина действий Apple.

    Как угадал еще год назад сайт macresearch.com, это также связано с «войной за многоядерность», что и было подтверждено в июне 2009-го года: компания Apple выпустила «технологический» бриф, посвященный работе Grand Central Dispatch (одного из ключевых элементов Mac OS X 10.6 Snow Leopard).

    Grand Central Dispatch позволяет с легкостью манипулировать различными очередями с блоками кода (об этом очень интересно написано в брифе), позволяя более эффективно использовать ресурсы многоядерных систем.

    Как это выглядит со стороны программиста?


    Понять это могут разработчики, имеющие доступ к XCode из Snow Leopard… а также все, кто установит PLBlocks toolchain/runtime для Mac OS X 10.5. Данный проект содержит в себе «расширенный» GCC, плагин к XCode и необходимые фреймворки. Откуда взялся этот код? Автор PLBlocks фактически портировал на 10.5 патчи к GCC от самой Apple. Установка описана на странице проекта и сложностей не представляет.

    Пример кода, написанного мною за 15 минут:

    #include <stdio.h>
    #include <string.h>

    void run_callback(char *s, void (^callback)(int len)) {

        printf(" %s:", s);
        callback(strlen(s));
    }

    void print_numbers(int *array, size_t array_size, int (^chooser)(int)) {
        int i;
        
        for (i = 0; i < array_size; i++)
            if (chooser(array[i]))
                printf("%4d", array[i]);
        
        printf("\n");
    }

    int main (int argc, const char * argv[]) {
        void (^testblock)(char *);
        
        testblock = ^(char *s) { printf("String is %s\n", s); };
        testblock("TEST!");

        
        int test[] = { -1, 5, 91, -45, 0, 4, -43, 42 };
        int len = sizeof(test)/sizeof(int);

        printf("all numbers:\n ");
        print_numbers(test, len, ^(int n) {
            return 1;
        });
        
        printf("positive only:\n ");
        print_numbers(test, len, ^(int n) {
            return n > 0;
        });
        
        
        int factor = 2;
        printf("another demo..\n");    
        run_callback("hello", ^(int len) {
            int i;
            for (i = 1; i <= len*factor; i++) printf("%3d", i);
            printf("\n");
        });
        
        return 0;
    }


    * This source code was highlighted with Source Code Highlighter.

    Результат выполнения:

    String is TEST!
    all numbers:
    -1 5 91 -45 0 4 -43 42
    positive only:
    5 91 4 42
    another demo…
    hello: 1 2 3 4 5 6 7 8 9 10


    Пример очень простой; безусловно, тема блоков кода в C/Obj-C и использования Grand Central Dispatch гораздо шире и глубже.

    Что еще почитать?


    Специально отобранные материалы для дальнейшего чтения (англ.):
    Ждем релиза Snow Leopard и нового XCode. Вместе с тем, пока нет никаких подтверждений тому, что блоки появятся также и в iPhone OS (если не считать упомянутой реализации PLBlocks).

    В общем, это прекрасно.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 57
    • 0
      Ах, да. Для переноса в тематический блог («языки программирования»?) пока не хватает кармы.
    • 0
      А чем отличается от c++ closures, появившихся в последнем стандарте — какая-то еще поддержка со стороны рантайма?
      • +2
        Мы вот вот об этих closures?

        Признаться, я пока не очень хорошо знаю пока си-плюс-плюсные closures, но поддержка со стороны рантайма, конечно, есть — чтобы обеспечить objective-c memory management (кстати, в obj-c блок кода является «id» и даже понимает пару методов — по-крайней мере, пока несколько).

        Думаю, и foundation будет расширена для того (хотя это не совсем рантайм) — для поддержки, например, красивых итераторов (мне этого очень не хватало после Смоллтока). Плюс вот здесь хороший пример.

        (я специально брал пример на Си, чтобы максимально наглядно продемонстрировать синтаксис и легкость использования)

        Посмотрим, что нам и Grand Central Dispatch принесет… это вообще тема для отдельного исследования. Суть в том, что очередями, содержащими блоки кода, будет управлять подсистема на уровне операционки. В брифе на эту тему немного есть. Вот, скажем — «In addition to scheduling blocks directly, you can associate a block and queue with an event source such as a timer, network socket, or file descriptor. Every time that source fires, a new copy of the block is added to the queue. This allows rapid response without the expense of polling or “parking a thread” on the event source» — разве не мило?

        Чем Apple и приятна — в ее случае closures не есть изолированная технология, это сразу целостная идея о том, как ее использовать.
        • +1
          Т.е., если посмотреть на эти аргументы, это не только closures, а скорее coroutines: с соответствующей поддержкой со стороны рантайма, с планировщиком.

          Интересно :)
          • 0
            Весьма интересно, точно.

            Я удивлен, что об этом так мало написано, зато все так яростно обсуждают новый expose mode в 10.6 (который очень симпатичен, впрочем).

            Впрочем, что удивляться… non-disclosure agreement же.

            Специально весь текст писал по материалам в открытом доступен (да и не у меня пока ADC Select Membership :)
      • 0
        спасибо за новость, пойду наконец-то скачаю Snow Leopard.

        Вот если бы Apple еще добавила в Objective-C возможность пользоваться базовыми сишными типами(int, float, ...) как классами-наследниками NSObject, чтобы можно было без проблем писать [myArray addObject:25], было бы вооще замечательно(про NSNumber знаю, но с ним возится долго)

        Ну и перегрузку операторов неплохо бы…
        • 0
          Угу, есть некая печаль в том, что в obj-c есть базовые типы, а есть объекты. Что даже странно — когда они тянули свои идеи с того же Смоллтока, могли бы и его идею «все — объект» захватить с собой. Очень удобно.

          Перегрузку операторов я считаю вредной :) Разве что для строк сделать какой-нибудь syntactic sugar.
          • 0
            И для массивов, ибо [[array objectAtIndex:i] objectAtIndex:j] уж как то слишком длинно…
            • 0
              Где-то видел пример, в котором классу NSArray была дописана категория с функцией двоеточие, прототип которой выглядел примерно так:
              — (id): (int) index;
              Функция выполняла ровно то же, что и objectAtIndex, но ее название гораздо короче.
              Работала так: id fifthElement = [array: 5];

              Мне кажется ее несложно написать самому и использовать в своих проектах.

              • 0
                хм, хорошая мысль попробуем :)
                • 0
                  хотя не, всё почти тоже самое получается, просто я привык воспринимать взятие индекса чуть ли ни как часть имени переменной, а пробел и квадратные скобки для сообщения все портят, хотя такая запись все таки покороче чем objectAtIndex: :)
                  • 0
                    typedef поможет
                    • 0
                      Как? жду примера) понимаю еше что то из макросов но через typedef :D
                      • 0
                        Да и макросы тут не смогут сделать аналог С синтаксиса для массивов, нужно только решение на уровне синтаксиса языка.
                • 0
                  ну возможно потому что использование раздельно Си и ObjC типов дает нихилое ускорение и возможность бесболезненного использования Сишного кода и библиотек. Хотя если бы написали правильный препроцессор с заменой Сишных типов на NSNumber в нужных местах, то было бы все ок.

                  Перегрузку операторов я считаю вредной :) Разве что для строк сделать какой-нибудь syntactic sugar.
                  ну всяко прятней писать
                  myarray[15]
                  вместо
                  [myarray objectAtIndex:15]
                  ведь необзяательно добавлять что-то в глубь языка, можно просто сделать на уровне syntax sugar
                  • 0
                    Ну опять же если дать девелоперам возможность писать Array[i][j] для не NSArray то вполне возможно что многие перестанут пользоваться Сшными, а они мягко говоря быстрее чем NSArray
                    • 0
                      Извиняюсь, опечатка надо «писать Array[i][j] для NSArray „
                      • 0
                        да это понятно, что указатель на указатель будет всяко быстрее, чем NSArray, но все-таки все все-равно используют его, так почему-бы и не сделать
                      • 0
                        typedef не поможет?
                • 0
                  Oh yes baby!!!
                  После руби очень не хватает подобного функционала в Objective-C :)
                  • 0
                    Самое забавное, что это не бумажный стандарт, а штука, которую я только что запускал на компьютере :)
                  • +1
                    Ну выглядит как-то попонятнее и попроще, чем замыкания из C++0x.
                    • +1
                      Да, Вы правы. Если Apple это продвинет «везде» (в смысле, в рамках своих SDK) — будет приятно.

                      По-большому счету, я взял самый простой пример для того, чтобы проиллюстрировать простую вещь: этот код может читать любой Си-программист (даже ничего не знающий о сложных теоретических дискуссиях и не читавший километры книг).

                      P.S. Я вообще плохо переношу C++; в данном случае, Obj-C — меньшее из зол. Надо будет как-нибудь написать статью про причины и историю появления Objective-C.
                    • 0
                      Интересно, а эти патчи нельзя прикрутить к gcc на других платформах?
                      • 0
                        Судя по тому, что автор PLBlocks сделал порт для Apple iPhone — можно. Но боюсь соврать, я не лез на source-level компилятора.
                      • –5
                        Хм, Apple нарушает совместимость кода, разбивая переносимость ПО — одного из основ разработки ПО, а вы этому и рады?! Это же прямые нарушения стандартов С и С++! Такими вещами нельзя пользоваться. В особенность это качается С++ — стандарт на носу, а они вводят упрощенные замыкания в обход новому функционалу…
                        • +1
                          Большая часть MacOS (Cocoa) и iPhone OS написана на Objective-C — языке, который за пределами мак-мира никто, по сути, и не использует.

                          Да, они добавили совсем недавно в Obj-C 2.0 сборщик мусора и properties… мир, кажется, устоял. Теперь там появились замыкания.

                          Apple не выпускает средства разработки под любые другие ОС, кроме своей, поэтому:

                          1) она не слишком влияет на мейнстрим C++
                          2) ее не слишком волнует мейнстрим C++

                          Тот факт, что использовать замыкания можно и в чистом Си — исключительно любовь apple к облегчению жизни разработчика (ну и, возможно, необходимость поддержать code blocks на уровне ядра и системных сервисов, написанных на C/C++).
                          • 0
                            Я не говорю про Objective-C — пусть улучшают данный язык, я только «за». Но вот то же самое вводить в С и С++ в обход стандартам не есть правильно.
                            • +1
                              Поскольку замыкания в C/C++ теперь официально есть только под Mac OS, то главная задача других систем — не поддаться соблазну :)

                              Слава Богу, эта не та ситуация, когда сайт оптимизируется под Firefox, но обязан показываться и в Опере. Софт под Мак/iPhone пишется исключительно под Мак/iPhone. Apple навязала всем Obj-C при разработке под iPhone — и мир стерпел (как стерпел в свое время слоты и moc в Qt; аналогия не так глупа, ведь весь ObjC, по сути — умный препроцессор к Си и тоненький рантайм)

                              Ну и потом, хочется же вечеринку.
                              • –2
                                >> Софт под Мак/iPhone пишется исключительно под Мак/iPhone.
                                Вот об этом и речь — смогу ли я использовать наработки программистов, которые используют нестандартный код? Нет. Или даже так: могут ли быть уверены Apple-программисты, что завтра их код не понадобится перекомпилировать компилятором Intel (хотя бы, чтобы повысить скорость выполнения части кода)? Не может. Программисты, использующие не стандартные конструкции языка не могут считаться профессионалами — они не думают о будущем. И да — Apple это выгодно, получается переносимость кода в одну сторону — на платформу Apple, но не наоборот.
                                • +1
                                  Я мог бы возразить, что абсолютно переносимый код зачастую несколько хуже родного (wxWidget vs Cocoa?). Мог бы сказать, что проф. программисты под Windows вполне себе продолжают считаться профессионалами, несмотря на то, что WTL/MFC не собирается под Unix.

                                  Но то GUI, будем считать его platform specific. Спустимся ниже. Я понимаю, библиотеки общего назначения нужно переносить, да?

                                  Но вот смотрите — в свое время потребовалось сделать event-driven library для работы с сетью и низким overhead.

                                  Чем кончилось? Я напомню: kqueue (FreeBSD), rt signals (Linux 2.2.19+), /dev/poll (Solaris 7 11/99+), event ports (Solaris 10). У всех — свои реализации и свой API.

                                  Решение? libevent в итоге поддерживает их все. Равно как и nginx, о котором так много пишут последнее время.

                                  Выходит, можно как-то выкрутиться.

                                  Apple всегда выглядела хорошо, потому что одновременно выпускала и софт, и железо. Последнее время они идут дальше — они не только делают platform specific API (как и все), они меняют под него язык. Благо, Obj-C кроме них никому не нужен, не так ли?

                                  И тем не менее, есть попытки поддерживать Cocoa под Windows: www.cocotron.org/. Ведь формально Apple блюдет букву opensource — любой gcc умеет компилировать код Objective-C. Даже к Blocks исходники уже отданы всем желающим.

                                  Повторюсь — на мой взгляд, все эти closures сделаны в первую очередь для ObjC. То, что они поддерживаются в чистом C/C++ (а мой пример в XCode был собран как command line C utility project) — чисто для удобства.

                                  Что, мир сильно волнует наличие garbage collector'а в ObjC? он не заметит и closures, поверьте :)
                                  • 0
                                    Эх, Вы опять в обсуждении С и С++ перешли на ObjC (я уже понял, что Вы не любите С++). Все что касается ObjC — я с Вами согласен. Но речь не о нем.
                                    GUI и API — не входят в «ядро» языков C и С++ — их нет в стандарте! В С++ в стандарте появятся ФП-конструкции, которые (если я в верно понял из данного топика) были в упрощенном виде, с поддержкой ОС, но с отличным синтаксисом введены в gcc c соответствующим патчем. В чем проблема помочь разработчикам gcc реализовывать стандарт (этот вопрос только по С++), а не писать свой (не совместимый со стандартом) патч или следовать практически принятому синтаксису ФП-выражений (по ссылке: The syntax of blocks and C++ lambdas are completely different)?

                                    Возможно ответ кроется в каких-то координальных отличиях blocks от C++-lambda. Можете их перечислить по пунктам?
                                    • 0
                                      Не могу. Я не изучил еще C++ lambda в деталях. Из чисто академического интереса я хочу это сделать (тогда как Blocks я изучу из соображений чисто практических).

                                      «В чем проблема помочь разработчикам gcc реализовывать стандарт (этот вопрос только по С++), а не писать свой (не совместимый со стандартом) патч»

                                      Это очень хороший вопрос, кстати. У меня есть версия.

                                      ObjC — надстройка над C. Он не использует фишек C++; ObjC — это просто «Си-с-объектами».

                                      Таким образом, развитие C++ никак не поможет развитию ObjC — тогда как все приложения в Mac OS и iPhone OS пишутся именно на ObjC.

                                      Иными словами, как мне кажется, Эпплу просто нет никакого повода вкладывать силы в развитие C++: они сделали ставку на ObjC, а в силу его природы, некоторые их нововведения оказываются доступными и в C/C++-приложениях.

                                      Почитайте clang.llvm.org/docs/BlockImplementation.txt — даже здесь не задействовано ни одной C++-фишки.
                                      • 0
                                        В чем проблема помочь разработчикам gcc реализовывать стандарт (этот вопрос только по С++), а не писать свой (не совместимый со стандартом) патч или следовать практически принятому синтаксису ФП-выражений (по ссылке: The syntax of blocks and C++ lambdas are completely different)?
                                        Для особо одаренных, объясняю еще раз:
                                        1. в топике говорится про стороннюю реализацию. Что сделает Apple достоверно будет известно с выходом Snow Leopard
                                        2. сторонняя реализация написана исключительно на Си(нечего специфически Си++сного там нет). Поскольку в C++ может использовать Си код, то эта реализация автоматически позволяет(но не заставляет) использовать блоки в С++

                                        что тут не ясно?
                                        • 0
                                          Одними словами пишем практически.
                                    • 0
                                      Как будто microsoft этого тоже не делает — переносимость кода в сторону ms легко, обратно — тяжело. Гляньте как игры портируются на мак — путём подкручивания Cider или Cedega (это wine). Сели на DirectX и уже не перелезут на OpenGL.
                              • 0
                                кстати, сопоставьте два факта.

                                C++0x сделан в 1998-2003 и еще Бог знает когда станет мейнстримом.

                                Анонс Blocks сделан год назад и полностьюё реализован в среде разработке Snow Leopard, которую любой желающий скачает через полтора месяца и начнет использовать в своих приложениях.

                                Ничего не напоминает? w3c, нет?
                                • 0
                                  >> C++0x сделан в 1998-2003 и еще Бог знает когда станет мейнстримом.
                                  Нет, он еще не сделан. Как показала недавняя история с концептами — стандарт в разработке. Но это не меняет ситуацию. Хотя бы этого стандарта и не было вовсе, ответственность программиста за переносимость его кода лежит на самом программисте. И насчет «Бог знает когда станет мейнстримом» — что Вы имеете ввиду? Использоваться функциональный стиль в языке станет сразу же после принятия стандарта — компиляторы уже вплотную подошли к поддержке этого стиля уже сейчас, а после принятия стандарта очень быстро допилят поддержку ФП-фич.
                                  • 0
                                    Я чуть выше писал — прелесть ситуации с closures в XCode в том, что она предстает не как «ой, мы тут добавили нечто экспериментальное», а в том, что она сразу глубоко интегрируется с SDK и операционной системой. Целостный подход.

                                    В каком-то смысле можно считать, что Snow Leopard обкатывает идею «closures в си-подобных языках» на живых людях :)

                                    p.s. простите, не знал, что стандарт «еще не сделан», хотя про концепты читал. Ну так… когда? Годы идут. Эффективность и читаемость кода нужна сейчас. Ждать, пока все определятся со стандартами и ничего не делать все это время? Есть такой анти-паттерн, Premature Generalization.

                                    К тому же closures почти наверняка не вылезут за пределы OS X / iPhone OS X, как оттуда не вылезла умнейшая Cocoa (воспринимая после MFC как рай земной).
                                • +1
                                  Apple нарушает совместимость кода, разбивая переносимость ПО — одного из основ разработки ПО, а вы этому и рады
                                  нет, мы рады тому, что в Objective-C буду замыкания. И будут они по стандарту(дабы вас успокоить).

                                  Будут ли они также в С и С++ мы не знаем. В сторонней реализации замыканий, описанной в этой статье, они присутствуют. Будут ли они в реализации от Apple — пока еще не знаем(или не говорим из-за NDA). Тем не менее, если они и будут, то Apple несомненно будет их проталкивать в новые стандарты.

                                  Теперь Вы спокойны?
                                  • 0
                                    Если их не будет в С и С++, то спокоен :)
                                    • +1
                                      как знать :) javascript изначально появился как внутренний язык в netscape browser :)
                                      • +2
                                        в Objective-C стандарте они будут потому как его де-факто устанавливает Apple.

                                        В стандарт С они будут его проталкивать. До того времени как это произойдет, они все-равно будут использовать Blocks, а для всех остальных буду писать предупреджения, мол поддерживается только нашим компилятором, будте осторожны.
                                        • 0
                                          С является подмножеством Objective-C, так что воспринимайте это не как введение замыканий в С, а как введение замыканий в С-шную часть Objective-C и будьте спокойны:)
                                          • 0
                                            Достаточно добавить поддержку этого в gcc. Эппл сам пользуется gcc и имеет доступ изменять его в транке. А как показывает практика, то, что есть в gcc, рано или поздно просачивается в стандарты.
                                      • 0
                                        Гм, а как замыкания реализованы технически? Они принимают параметры по значению или по ссылке? Во втором случае есть вероятность же есть, что перемнная сдохнет до того как будет вызвано замыкание!

                                        И как это способствует оптимизации на многоядерных процесорах?

                                        • 0
                                          Я так старался расставлять ссылки…
                                        • 0
                                          Как-то из статьи совсем не вытекает, чем будут полезны замыкания в Obj C. Очевидно, что это хороший syntactic sugar, но не очевидна реальная польза. К тому же в примерах, подобные фишки можно было провернуть с помощью указателей на функции, т.е. функционал — не специфичен только для замыканий.
                                          • +1
                                            Я надеялся на принцип sapienti sat, поэтому не разжевывал. Статья — не столько тьюториал, сколько «расширенная новость». Зато в ней, например, отличнейшие тексты по ссылкам (с разнообразными примерами).

                                            Безусловно, Вы правы. Все можно провернуть с помощью указателей. Объекты тоже можно сделать с помощью структур и ассоциированных с ними функций (как оно и происходит «внутри»). В итоге все можно написать на ассемблере.

                                            Вопрос в удобстве и затраченном времени.

                                            Вероятно, суть в том, что для эффективного использования closures к ним нужно несколько привыкнуть и увидеть в деле. Вон, программисты на Ruby выше в комментариях уже высказались :)

                                            Если тема интересна, я продолжу на нее писать. Доберемся и до use cases в obj-c.
                                          • 0
                                            > Ждем релиза Snow Leopard и нового XCode.
                                            Что, без этого никак? У Apple, вроде, никаких эксклюзивных компиляторов нет, просто gcc + llvm, не так?
                                            • 0
                                              Apple именно что вносит свои собственные правки в gcc.

                                              Часть из них попадает назад, в основную ветку gcc, а часть — нет (несмотря на то, что apple честно выкладывает все исходники). К примеру, они здорово, улучшили ARM-порт gcc, когда запускали свой iPhone.

                                              «This file describes Apple's version of GCC 4.x modified for Darwin /
                                              Mac OS X. Although Apple's stated policy is to contribute all of its
                                              GCC work to the FSF GCC mainstream, at any given moment there will be
                                              changes that are permanently unacceptable for FSF GCC, in need of
                                              rework before acceptance, or that we simply aren't ready to send in.
                                              This version of GCC contains all those changes.»

                                              Вот и тут аналогичная ситуация. Gcc с поддержкой блоков у Apple уже есть в исходниках. Автор PLBlocks взял его и скомпилировал для 10.5.

                                              Другое дело, что в Developers Tools в 10.6 он пойдет by default. Да и XCode научится правильно понимать новый синтаксис.
                                              • 0
                                                … плюс новые фреймворки с поддержкой Blocks. Точно пока можно сказать только про Grand Central Dispatch (см. pdf выше), но не могут же они ограничиться только им…
                                              • 0
                                                Если кратко — скачайте plblocks по ссылкам выше, поставьте на 10.5 и скомпилируйте код выше. Он работает.

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