Я — тот ещё фрукт. Все мои личные игровые проекты, которыми я занимался в последнее время, были написаны на «vanilla» C. Больше никто так не делает, поэтому, полагаю, вам может быть интересно узнать, почему я сделал такой выбор.
Написанное дальше содержит мнение о языках программирования, которое вам может не понравиться. Я предупреждал.

Что мне нужно от языка


Некоторые требования не подлежат обсуждению или поиску компромиссов. Во-первых, язык должен быть надёжным. Я не могу позволить себе тратить своё время на поиск ошибок, которых я не совершал.

Я написал большое количество игр на Flash, и вот, Flash умер. Я не хочу тратить время на портирование старых игр на современные платформы, я хочу писать новые игры. Мне нужна платформа, в долговечности которой я буду уверен.

Чего я точно хочу, так это избежать зависимости от определённой ОС. В идеале — иметь возможность разрабатывать и для консолей. Поэтому важно, чтобы язык позволял легко портировать написанное на нём, а также имел хорошую поддержку кроссплатформенных библиотек.

Чего я хочу от языка


Самым важным, но не обязательным требованием является простота. Изучение особенностей языка и и его чудного «умного» API я нахожу безумно скучным. Идеальный язык можно однажды изучить и никогда больше не пользоваться его документацией.

Поиск и исправление багов истощает творческий потенциал. Я хочу оставлять меньше багов, потому желаю строгую типизацию, качественные сообщения об ошибках и статический анализ кода. Хочу упростить поиск ошибок, а, следовательно, хорошие отладочные средства и динамический анализ.

Меня не интересует красивая реалистичная картинка, зато я забочусь о производительности. Меньшая требовательность к ресурсам расширяет спектр возможностей, доступных для реализации. Особенно интересно наблюдать за тем, что происходит с современным мощными компьютерами, когда разработчик о производительности не думает.

Ещё больше меня волнует скорость компилятора. Я не какой-нибудь буддийский мастер концентрации, и ждать больше 10 секунд — расточительство. Хуже того, это выбивает из потока. Вроде только глянул Twitter, а 5 минут куда-то пропали.

Я не адепт ООП. Большую часть времени, проведённого за работой, я имел дело с классами и объектами. Но чем дальше, тем меньше я понимаю, почему надо так жёстко объединять код и данные. Я хочу работать с данными, как с данными, и писать код, который лучше всего подходит в конкретной ситуации.

Альтернативы


C++ продолжает оставаться наиболее распространенным языком для разработки игр, и на то есть свои причины. До сих пор большинство моих заказных проектов пишется на нем, и это мне не нравится.

C++ покрывает мои нужды, но не соответствует желаниям. Он дико сложный. Несмотря на наличие годных инструментов, на нём легко допускать коварные ошибки. Кроме того, по сравнению с C, он медленно компилируется. C++ имеет высокую производительность и предоставляет возможности, которых нет в C, но это не то, чего я хочу, да и достигается это ценой большой сложности.

C# и Java имеют схожие проблемы. Это многословные и сложные монстры, а мне нужен маленький простой зверёк. Оба языка направляют программиста прямиком в пучину ООП, а я против этого. Как и в большинстве высокоуровневых языков, многие сложные вещи тут скрываются так, что ничего не мешает случайно выстрелить себе в ногу.

Мне очень нравится Go. Во многих аспектах это изобретённый заново C, с поправкой на то, что до представления его публике он продумывался несколько лет. Я хотел бы использовать Go, но есть один огромный подводный камень — сборка мусора. Разработка игр на Go сомнительна, ведь сборщик мусора будет приостанавливать весь игровой мир, чего разработчик не может позволить. Также тут всё не очень хорошо с игровыми библиотеками. И хотя всегда можно приспособить для этого дела библиотеку на C, причём без особых проблем, это всё равно порождает много лишней работы. Кроме того, у меня есть сомнения насчёт перспектив. Go был бы неплох для веба, но это стремительно меняющаяся среда. Особенно это почувствовалось со смертью Flash.

JavaScript мне абсолютно не нравится. Он предоставляет столько свободы, что мне непонятно, как люди умудряются писать сколько-нибудь сложные проекты на нём. И не хочу даже пытаться его пробовать.

Haxe выглядит гораздо перспективнее остальных языков в этом списке. У него нет проблем с библиотеками. Если я снова начну писать под веб, то обязательно познакомлюсь с ним поближе. Несколько беспокоит относительная молодость языка, будет ли он жить? Больше мне добавить нечего, с Haxe я успел лишь немного поиграться, не углубляясь.

Джонатан Блоу пишет свой язык. Язык, которым он сам захотел бы пользоваться. Я восхищаюсь его решением, иногда и сам загораюсь идеей поступить так же. Но не выкинуть же все существующие библиотеки. А реализовать полную с ними совместимость — не так просто. Да и вообще это трудно, я бы предпочёл дальше писать игры, а не языки программирования.

Почему C — лучший выбор для меня


Хоть C и опасен, зато надёжен. Это очень острый нож, способный отрубить пальцы так же легко, как нарезать овощи. Но он прост, и научиться правильно его использовать труда не составит.

Он быстрый. А когда дело доходит до компиляции, я и представить себе не могу, что какой-то язык способен сделать это быстрее.
Есть возможность писать код так, чтобы он работал везде. И обычно это относительно несложно. Трудно представить, что однажды это изменится.

Есть отличная поддержка библиотек и инструментов.

Хоть меня это и несколько печалит, но C до сих пор остаётся лучшим языком для меня.

Я совсем не хочу сказать что-то вроде: «Эй, вы тоже должны писать на C». Я осознаю, что мои предпочтения весьма специфичны. Кроме того, по количеству, написанного мной на разных языках, код на «vanilla» C занимает лидирующую позицию, так что это уже часть моей зоны комфорта.

Так что да, C для меня — лучший выбор.

От переводчика


Перевод местами достаточно вольный, но не в ущерб смыслу или содержанию.

Подготовил перевод специально к пятнице, в этот день он особенно уместен, на мой взгляд. Хоть автор оригинального текста и пишет, кажется, на полном серьезе… вы сами всё понимаете, если прочитали. Как истину прочитанное воспринимать не стоит.

С предложениями, пожеланиями и замечаниями, как обычно, в ЛС.

Комментарии (251)


  1. a553
    15.01.2016 00:19
    +65

    Я хочу оставлять меньше багов, потому желаю строгую типизацию, качественные сообщения об ошибках и статический анализ кода. Хочу упростить поиск ошибок, а, следовательно, хорошие отладочные средства и динамический анализ.
    А Си-то тут причём?)


    1. gwer
      15.01.2016 00:23
      +44

      ?\_(?)_/?


    1. IRainman
      15.01.2016 02:54

      Перевод же.


  1. tmnhy
    15.01.2016 00:24
    +6

    А где сами игры то? Хоть на Си, хоть на Go…


    1. gwer
      15.01.2016 00:25
      +2

      На сайте автора: jonathanwhiting.com


      1. alekciy
        15.01.2016 09:56
        +5

        Мдя… игры выглядят как архтефакт 80-90-ых. Как то сразу вспомнились 8 бит и денди.


        1. EvilPartisan
          15.01.2016 12:29
          +5

          Ныне очень модное явление в Steam. Но многие из них, даже с такого уровня графикой, умудряются как-то многовато ресурсов жрать.


          1. gwer
            15.01.2016 12:30
            +2

            Потому что написаны на чём? Правильно, на чём угодно, но не на C. И даже не на плюсах наверняка. «Мы же пишем как бы старую игру на новые машины, тут производительность огого!»


            1. KumoKairo
              15.01.2016 12:45
              +3

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


              1. gwer
                15.01.2016 12:50
                +4

                Медленного монстра можно написать на чём угодно. Быстрого — нет. Впрочем, это вопрос задачи. Нередко для части, требующей хорошую производительность, пишут отдельный модуль на более подходящем языке.


            1. NElias
              19.01.2016 23:44
              +1

              Язык здесь не при чем. Оптимизация ведется на другом уровне — модели, текстуры, хитрые подмены 3d на 2d и прочие трюки. Ну а самое главное шейдеры — скелетная анимация, свет, тени и прочее. Сейчас большинство вычислений в играх делает на GPU.


      1. Lertmind
        15.01.2016 12:59
        +1

        Кстати, первые 8 игр на C, следующие 17 на Flash.


        1. gwer
          15.01.2016 13:02
          +3

          Полагаю, вверху новые. Автор же сам пишет, что раньше писал на Flash, а потом тот умер.


  1. CodeRush
    15.01.2016 00:43
    +53

    Ну что сказать, это личный кактус отдельного человека, и он готов его кушать.
    Я пишу на C потому, что именно на нем весь UEFI и написан, но я с удовольствием перешёл бы на Rust прямо завтра, если бы такая возможность была, т.к. от некоторых особенностей C уже мутит.
    Синтаксис указателей на функции понимают два с половиной специалиста, молчаливое приведение типов приводит к очень хитрым ошибкам, от которых не спасает даже статический анализатор, практически все функции для работы с форматной строкой — одна большая дыра в безопасности, забытый volatile моежт обрушить цивилизацию в самом неожиданном месте, а макросами можно отстрелить себе не то, что ногу, а вообще все и несколько раз. Добавим сюда ручное управление памятью, которое почти никто не умеет делать правильно, буфера постоянного размера на стеке, и великий и ужасный NULL — изобретение на минус миллиард долларов. Несмотря на все это, С — прекрасный кроссплатформенный ЯП низкого уровня, и на низком уровне ему альтернатив практически нет. Подходит ли он для игр — надо спросить у автора, если он когда-нибудь вылезет из отладки.


    1. monah_tuk
      15.01.2016 07:39
      +6

      Синтаксис указателей на функции понимают два с половиной специалиста

      да что тут такого:
      void (*variable)(int, int);
      

      или
      вовзращаемое_значение (*имя_переменной)(аргументы);
      

      для объявления типа всё то же самое:
      typedef вовзращаемое_значение (*имя_типа)(аргументы);
      


      или через using в C++11:
      using имя_типа = вовзращаемое_значение (*)(аргументы);
      


      С указателям на методы класса (C++) чуточку сложнее, но тоже не rocket science, просто перед "*" добавляется Clazz::
      вовзращаемое_значение (Класс::*имя_переменной)(аргументы);
      typedef вовзращаемое_значение (Класс::*имя_типа)(аргументы);
      using имя_типа = вовзращаемое_значение (Класс::*)(аргументы);
      
      Правда с вызовом чуточку по другому:
      Clazz foo;
      (foo.*some_variable)(parameters);
      Clazz *bar = new Clazz;
      (bar->*some_variable)(parameters);
      


      В обоих случаях нельзя хранить указатели в void*, как бы того ни хотелось — это отличие от обычных указателей нужно запомнить, хотя компилятор должен выдать предупреждение.


      1. CodeRush
        15.01.2016 08:17
        +15

        Все хорошо, да. А теперь то же самое, но для функции, которая сама указатель на другую функцию принимает, как qsort из стандартной библиотеки. Необходимость в typedef сразу же указывает на проблему, а если его не использовать, получится дикая смесь из скобок, запятых и имен типов, которую невозможно ни толком прочитать, ни толком понять.
        Плюс еще нужно о соглашении о вызовах не забыть, если предполагается, что программа будет использоваться на голом железе, причем ключевое слово для него не стандартизировано и потому выглядит как макрос EFIAPI, который раскрывается либо в "", либо в __cdecl, либо в __attribute__((cdecl)), либо еще в какой-нибудь __кошмар.
        Честно сказать, я не знаю, как нужно было сделать лучше. Но тот факт, что указатели на функции в их нынешнем виде мало кто понимает — вижу на работе стабильно раз в месяц.


        1. monah_tuk
          15.01.2016 09:32
          +2

          а если его не использовать, получится дикая смесь из скобок, запятых и имен типов, которую невозможно ни толком прочитать, ни толком понять.

          почти Lisp :-)

          Плюс еще нужно о соглашении о вызовах не забыть, если предполагается, что программа будет использоваться на голом железе
          Мне кажется, что это к C, как таковому, имеет сильно посредственное отношение: трудно стандартизовать то, что может поменяться. Вдруг кто напишет OS, где будет принято аргументы в функцию передавать через один: через стек, через регистр, через стек, через регистр, или передавать адрес возврата первым аргументом. Или последним. Или в середине. Ну и тяжёлое наследие x86. На x86_64 как бы не так много вариантов оставили. Ну и другие платформы есть.

          Но тот факт, что указатели на функции в их нынешнем виде мало кто понимает — вижу на работе стабильно раз в месяц.
          Вот тут, похоже, я встретился с тем, чего я не знаю или не совсем понимаю. По сути, какое отношение имеет указатель на функцию с соглашениями на вызов? Ну и примеры недопонимания можно привести, без вреда NDA и прочему POPI.


          1. EvilPartisan
            15.01.2016 09:46
            +3

            А чем вам typedef не нравится?


            1. monah_tuk
              15.01.2016 09:49
              +1

              Я ничего против него не имею.


            1. CodeRush
              15.01.2016 11:09
              +2

              Мне он не нравится тем, что я вынужден проходить цепочку из макросов и typedef'ов, чтобы понять, что это за зверь вообще и как он будет выглядеть из окна аппаратного отладчика. Т.е. одно дело, когда на тебя из этого окна смотрит целая переменная со значением 17, и совсем другое — когда это не целая переменная, а указатель на целую, или на функцию, что еще хуже.
              Сам по себе typedef — это благо, а проблемы такого рода решаются грамотными IDE, но они от этого не перестают быть проблемами.


          1. CodeRush
            15.01.2016 10:53
            +5

            Я тут рассматриваю не только язык сам по себе, но и все, что вокруг, поэтому директивы компилятора, разные #pragma и прочие __attribute__((declspec)) я тоже отношу к C, просто не к чему больше. Не спорю, опять же, что стандартизировать такое сложно, однако #pragma STDC ... как-то пробрались в C99, значит не все еще потеряно в этом смысле.

            По поводу отношения соглашения о вызовах к указателям на функцию, простой пример: все компоненты UEFI находятся в одном адресном пространстве и общаются путем прямого вызова функций через таблицы указателей на них (такие таблицы называются «протоколами»). При этом, для архитектуры amd64 существует два распространенных соглашения о вызовах: Microsoft x64 (которое и используется в 64-битном UEFI и которое использует по умолчанию компилятор MSVC) и System V amd64 ABI, которое используют
            *nix-системы и которое по умолчанию использует GCC. При этом компоненты UEFI не собираются одним и тем же компилятором, и зачастую поставляются в бинарном виде, поэтому очень важно, чтобы соглашение о вызовах было одинаковое, а это достигается добавлением EFIAPI ко всем typedef'ам всех указателей на функции, являющиеся частью протоколов, к прототипам и реализациям этих функций.

            Пример кода
            #include "Uefi.h"
            
            // Define SIO DXE protocol GUID
            #define EFI_CRSIO_DXE_PROTOCOL_GUID { 0xc38bdbd, 0x6f6b, 0x49ae, 0x99, 0x5a, 0x1d, 0x6c, 0xc2, 0x9d, 0x95, 0xa1 }
            
            // Extern the GUID for protocol users.
            extern EFI_GUID gEfiCrSioDxeProtocolGuid;
            
            // Forward reference for ANSI C compatibility
            typedef struct _EFI_CRSIO_DXE_PROTOCOL EFI_CRSIO_DXE_PROTOCOL;
            
            // Define each protocol interface function and the respective function pointer type 
            typedef
            UINT16
            (EFIAPI *CRSIO_DXE_GET_INDEX) ( //Если вот здесь забыть EFIAPI, ничего не сломается, т.к. функция не имеет параметров. 
                VOID                        //А вот если бы они были, а компилятором оказался GCC, то он бы их положил в RDI, RSI...                         
            );                              //а функция их ждет в RCX, RDX..., т.е. на вид все хорошо, а по факту в регистрах мусор вместо параметров
            
            UINT16
            EFIAPI // А если забыть его вот здесь, не забыв выше, будет почти то же самое, только упадет все в другом месте
            CrSioGetIndex(
                VOID
            );
            
            // Define protocol data structure
            typedef struct _EFI_CRSIO_DXE_PROTOCOL 
            {
                CRSIO_DXE_GET_INDEX CrSioGetIndex;
            } EFI_CRSIO_DXE_PROTOCOL;
            


            1. monah_tuk
              17.01.2016 04:48
              +2

              А! Теперь понял, вы про информацию о соглашении на вызов в самой сигнатуре при объявлении переменной или типа.


          1. sulnedinfind
            16.01.2016 14:07
            +2

            почти Lisp :-)

            В Lisp хотя бы запятых нет :)


        1. MacIn
          16.01.2016 02:06
          +5

          А теперь то же самое, но для функции,


          Вроде такого (со SO):
          Consider the signal() function from the C standard:

          extern void (*signal(int, void(*)(int)))(int);
          
          

          Perfectly obscurely obvious — it's a function that takes two arguments, an integer and a pointer to a function that takes an integer as an argument and returns nothing, and it (signal()) returns a pointer to a function that takes an integer as an argument and returns nothing.



      1. webhamster
        15.01.2016 09:01
        -2

        >> Синтаксис указателей на функции понимают два с половиной специалиста
        > да что тут такого:
        > void (*variable)(int, int);

        И сразу вопрос из зала: где тут имя функции?


        1. monah_tuk
          15.01.2016 09:33
          +7

          Именно функции или переменной в которой можно сохранить указатель на функцию? ;-)


          1. webhamster
            15.01.2016 23:41
            -4

            Вот об том и речь, что понимают два с половиной специалиста


    1. AllexIn
      15.01.2016 07:58
      +4

      ручное управление памятью, которое почти никто не умеет делать правильно

      Два простых правила, чтобы забыть о проблемах с ручным управлением памятью:
      1) удаляем память там же где и создаем
      2) следующая вещь, которая пишется после new — это delete

      В тоже время особенности работы GC для каждого отдельно языка содержат многостраничные мануалы о том, как правильно управлять памятью, как делать нужно и как делать не нужно… Не говоря уж о тонне костылей, типа андроидовского Out of Memory, если у Bitmap не вызвать recycle.


      1. CodeRush
        15.01.2016 08:29
        +14

        А что делать с обработкой ошибок, копировать все вызовы free() в каждый if (EFI_ERROR(Status)) или использовать goto fail, или может быть do { if (error_condition) break; } while(0), если у вас на goto аллергия?
        Если бы простыми правилами можно было бы обойтись, память не текла бы у практически всех программ на С сложнее hello.c. Язык не виноват, но люди устроены именно так.


        1. monah_tuk
          15.01.2016 09:41
          +2

          А по мне, так это, пожалуй, единственный вариант где goto применим. Отчего аллергия-то? Ну или сделать свой аналог try/throw/catch/finally при помощи setjump/longjump если вообще сыпью покрываетесь :-)


          1. CodeRush
            15.01.2016 11:02

            По мне тоже, но случается и вот такое, причем у всех, даже у самых гурушных гуру. У нас там все проще в UEFI — прошивка отрабатывает быстро и умирает быстро, а всю память, выделенную как EfiBootServicesCode или EfiBootServicesData освободит менеджер BDS, просто пометив ее свободной в UEFI MemMap, и ее потом перепишет ОС, когда ей понадобится. Т.к. мало кто в прошивке пытается выделить себе с кучи гигабайт-другой, то вся система довольно спокойно отностится к утечкам — в конце все равно останутся только пара рантайм-сервисов, для которых управление памятью уже написано и работает нормально.


      1. webhamster
        15.01.2016 09:12

        > Два простых правила, чтобы забыть о проблемах с ручным управлением памятью:
        > 1) удаляем память там же где и создаем
        > 2) следующая вещь, которая пишется после new — это delete

        А что делать с событийной моделью, когда например работаешь с буфером обмена? В обработчике drag создается объект, указатель на который пихается в буфер, При drop объект должен быть удален. Получается что new и delete расположены вообще в разных местах. Ваши правила не работают.


        1. monah_tuk
          15.01.2016 09:38
          +2

          Для сложных случаев использовать подход, типа gobject с счётчиками и _ref/_unref? Ну как вариант.


        1. AllexIn
          15.01.2016 10:25
          +5

          Ваши правила не работают.

          Очевидно, что правила не работают, если их неправильно применять.
          Зачем вы в Drag суете указатель? Почему не сам объект, например? Он слишком большой? Тогда надо передавать не указатель, а его владельца с индексом, например.


          1. webhamster
            15.01.2016 23:44
            +1

            Да, он слишком большой.

            Какой индекс имеется в виду?


      1. crmMaster
        15.01.2016 10:13
        +5

        В C нет new и delete, там malloc и free — те еще кактусы, особенно в комплекте с привычкой C неявно приводить типы.


      1. mustitz
        15.01.2016 23:50
        +1

        У меня другие правила: (1) использовать valgrind, (2) функциональные тесты под valgrind.


        1. 1101_debian
          16.01.2016 09:55
          +1

          Можно подробнее о функциональных тестах под valgrind?


      1. R10
        17.01.2016 17:17
        +4

        В современном С++ new и delete не используются. Smart pointers (unique_ptr), RAII, move семантика решают проблемы с памятью. Проблема не с памятью, а с ownership, shared state и object lifetime. Многие проблемы «старого» C++ (до C++11) решены, но по-прежнему использование С++ требует высокой квалификации программиста. Фишка С++ в том что на нем можно писать как высокоуровневые вещи (в отличие от С) так и очень низкоуровневые (в отличие от Java/C#). Поэтому в game dev С++ основной язык. Rust, Go, D как системные языки — все еще несколько сыроваты на настоящее время.


      1. vladon
        18.01.2016 14:41
        +1

        Два простых правила, чтобы забыть о проблемах с ручным управлением памятью:
        1) удаляем память там же где и создаем
        2) следующая вещь, которая пишется после new — это delete


        А если между new и delete возникает исключение?

        Два простых правила:
        1) Не используем new и delete (если мы не писатели низкоуровневых либ)
        2) Используем умные указатели


        1. AllexIn
          18.01.2016 14:46
          +1

          Вы так говорите, как будто new и delete должны быть в одном методе.
          Если они в одном методе — они вообще не нужныю
          «Там же» — в том же логическом пространстве.
          По поводу smart_ptr… Холивар будет. :) Так что пожалуй не буду ничего писать.


          1. vladon
            18.01.2016 14:48
            +1

            С чего вы взяли, что я говорю, что они в одном методе? Я говорю между вызовами new и delete может возникнуть исключение.

            Напишите, что вас не устраивает в умных указателях, интересно же. Не холиварно, а конкретно.


            1. AllexIn
              18.01.2016 14:59
              +1

              А почему конкретно «исключение»?
              Может произойти тысяча вещей, которые поломают логику и эти вещи надо учитывать.
              Если исключение поломало нам все, то уже пофиг на утечку будет. Если же мы исключение нормально обработали или штатно подавили — оно не повлияет на дальнейший delete.

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


              1. vladon
                18.01.2016 15:02
                +1

                Исключение можно обрабатывать и позже, но leak ресурса уже возникнет. А так — RAII сработает при unwind'е.

                Ну ладно, один конкретный пример: нужно учитывать циклические ссылки и держать весь путь мигрированя указателя, чтобы не допустить цикличности. По сути это слабо отличается от необходимости держать такой же путь для обычного указателя, чтобы предсказуемо его удалить.


                Вы сейчас конкретно про shared_ptr.


              1. vladon
                18.01.2016 15:04
                +1

                Ну ладно, один конкретный пример: нужно учитывать циклические ссылки и держать весь путь мигрированя указателя, чтобы не допустить цикличности. По сути это слабо отличается от необходимости держать такой же путь для обычного указателя, чтобы предсказуемо его удалить.


                И, кстати, вы таким образом переизобретёте shared_ptr.


    1. potan
      15.01.2016 18:42
      +2

      В Rust хорошая интероперабельность с C (но не с C++). Может пора попробовать его использовать?


      1. CodeRush
        15.01.2016 19:33
        +3

        Уже однажды попробовал и не смог.
        Среда UEFI достаточно сильно отличается от привычной стандартной библиотеки, к примеру, там почти все строки — в UCS2, и уже одно это приносит кучу боли, т.к. строковые литералы просто как L«String» теперь не запишешь — в Rust UTF8 везде. Плюс абсолютно всё получается внутри unsafe {}, и в итоге преимуществ у Rust почти не остается, а недостатки вроде необходимости писать врапперы к библиотекам и протоколам — никуда не деваются. Я видел пару попыток, но их авторы тоже бросили, практически не начав.
        Если время найду, попробую еще раз.


    1. ToSHiC
      15.01.2016 19:39
      +1

      Кстати, а C++ без RTTI и stl имеет смысл использовать, сделав внешний интерфейс на чистом C, или слишком много внешних вызовов? По сути, использовать от C++ возможность работать с объектами, а не структурами (RAII для управления памятью/ресурсами), и шаблоны.


      1. CodeRush
        15.01.2016 19:45
        +1

        Не получится, т.к. нет рантайма (т.е new, delete и прочие красивости C++ просто не работают), а без него C++ мало чем лучше C. Вот тут Count Chu рассказывает, как он заводил код на C++ в EDK2, но успехом я такое решение точно не назову.


        1. ToSHiC
          15.01.2016 20:11
          +1

          Можно же сделать operator new (и остальные 3 штуки), которые будут звать malloc/free из «рантайма», который у вас уже есть. Или тоже не катит?


          1. CodeRush
            15.01.2016 20:40
            +2

            Катит, но там не только их не хватает, а в итоге нет ни исключений, ни стандартной библиотеки, и непонятно, зачем вообще огород городить, если на C уже все готово. В Rust хотя бы borrow checker поможет и иммутабельность по умолчанию, а чем хорош C++ в данном случае я просто не знаю.


            1. 0xd34df00d
              15.01.2016 20:58
              +2

              Note that C++ classes and templates (e.g. std::vector, std::string) actually aren't part of the C++ language. They are part of a library called the Standard Template Library.

              Подобные противопоставления очень сильно снижают доверие к источнику.


              1. CodeRush
                15.01.2016 21:13
                +1

                Тем не менее, даже гугловская libstdc++ не поддерживает STL, так что в каком-то смысле они тоже правы.


                1. 0xd34df00d
                  16.01.2016 17:18
                  +1

                  А ниже написано:

                  This runtime is an Android port of STLport (http://www.stlport.org). It provides a complete set of C++ standard library headers. It also, by embedding its own instance of GAbi++, provides support for RTTI and exception handling.

                  (курсив наш)

                  И кому верить?


                  1. CodeRush
                    16.01.2016 22:52
                    +1

                    Всем, libstdcpp и STLPort — два разных рантайма с разными же возможностями (и размерами), первый предосталяет только некоторые функции, а второй — всю стандартную библиотеку.


                    1. 0xd34df00d
                      17.01.2016 05:02
                      +1

                      Разве к этому нельзя относиться просто как к деталям реализации?


              1. R10
                17.01.2016 17:22
                +1

                В игровых движках на С++ как правило используют свои контейнеры и строки. STL используется, но в ограниченном объеме. Есть специально заточенные STL реализации типа EASTL, tinySTL.


                1. 0xd34df00d
                  17.01.2016 21:06
                  +1

                  Безусловно. Но это не лишает STL статуса части стандарта, а значит, и части языка.


            1. ToSHiC
              15.01.2016 21:01
              +1

              Блин, вот про исключения то я забыл, без них совсем печаль, да.


              1. 0xd34df00d
                15.01.2016 21:03
                +1

                Нормально без них и даже хорошо, я в своём коде вообще стараюсь уходить от исключений к монадической Either-подобной обработке ошибок.


  1. SAKrisT
    15.01.2016 00:47
    -18

    Автор зазнайка? Или это такой стиль? Везде «Я», в оригинале «I».
    Как-то тяжело читать.


    1. gwer
      15.01.2016 00:53
      +7

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


      1. Iceg
        15.01.2016 11:36
        +7

        Английский язык совсем не страдает от этого :) А вот переводы на русский — почти всегда.


    1. dannyzubarev
      15.01.2016 02:38
      -14

      Англичане жуткие собственники и частое повторение «I» в речи – абсолютно нормальное явление.


      1. burjui
        15.01.2016 14:29
        +3

        А, мне кажется, это связано с меньшим количеством падежей и гораздо меньшим их использованием в английском языке. В русском языке ситуация иная: во-первых, «я» склоняется по падежам (+ меня, мне, мной; в английском только + me), а во-вторых, местоимения часто можно опускать, т.к. их с успехом заменяют суффиксы глаголов (работаю, работаешь и т.п.).


        1. destroy
          18.01.2016 01:09
          +1

          Бедняжки, надо им отсыпать немного.


      1. qw1
        16.01.2016 19:48
        +1

        В научных работах часто предложение начинается с «We»


  1. k12th
    15.01.2016 00:50
    +9

    Ну, SDL-то написан на C, так что ничего особо удивительного в написании игр на нем нету.

    Меня не интересует красивая реалистичная картинка, зато я забочусь о производительности.
    А нахрена производительность в играх, кроме как на красивую картинку?:)


    1. gwer
      15.01.2016 00:54
      +1

      Якобы чтоб ограничения производительности не мешали ему внедрять новые фичи.


    1. Voiddancer
      15.01.2016 05:30
      +5

      1. k12th
        15.01.2016 11:44
        -2

        Таких игр — примерно одна на все остальные, и ОП не входит в число ее создателей, так что не считово:)


        1. poxu
          15.01.2016 12:10
          +2

          Таких игр — примерно одна на все остальные

          Minecraft, Terraria, Starbound, Gnomoria, Towns, Timber and stone, KeeperRL (open source кстати), CDDA.
          Это первое, что в голову пришло. А их ещё много.


    1. AllexIn
      15.01.2016 07:59
      +6

      SDL написан на С, чтобы его можно было подключить к любому языку.


      1. gurinderu
        15.01.2016 12:00
        +4

        Я думаю это не аргумент, с таким же успехом можно было написать SDL на с++.
        Я согласен в чем-то с автором, т.к. C очень хорош именно для игр.
        Весь opengl api это С, shaders тоже по сути C-like syntax. Так зачем использовать зоопарк языков, когда все можно писать на одном.


        1. AllexIn
          15.01.2016 12:05
          +3

          Написать на С++ и потом городить экспорт?
          Тем более SDL — набор отдельных модулей с низкой связанностью, без ООП там вполне можно жить.

          Я согласен в чем-то с автором

          Ну а я не согласен. Просто не могу представить архитектуру сколь-либо сложной игры на plain С. Может у меня заболевание мозга уже и я не мыслю программирования без ООП. Но весь опыт проектирования говорит мне, что С++ код при прочих равных будет чище аналогичного кода на plain C в сложной игре.

          Весь opengl api это С, shaders тоже по сути C-like syntax

          Поэтому все первым делом и пишут ООП обертку над OpenGL и шейдерами. :))
          Например, я не могу представить как будет выглядеть мультирендер на plain C.
          На С++ это просто абстрактный интерфейс и отдельная реализация для каждого рендера.
          А на plain C?


          1. iCpu
            15.01.2016 12:22
            +1

            Указатель на функцию? Я не защищаю C, но всё, что нужно помнить про ООП в C++ — это обёртка, скрывающая указатели от конечного программиста.


            1. AllexIn
              15.01.2016 12:32
              +1

              То есть лучшее решение — эмулировать ООП, вручную устанавливая указатели.


              1. iCpu
                15.01.2016 12:39

                «Эмулировать ООП» — это слишком сильный и смелый термин. В данном контексте даже неверный, ведь нужно просто хранить адрес следующей инструкции.
                Скорее обратно, ООП приходится реализовывать через такие грязные методы. Опять же, C++ — это не полноценный ООП, так как нету полноценных сигналов-слотов. Qt куда ближе, но он реализован через ещё более грязные методы: и строковые описания, и генерация методов, и куча чего ещё.


                1. AllexIn
                  15.01.2016 12:41
                  +5

                  А почему вы считаете что слот-сигнальная система является неотъемлемой частью настоящего ООП?


                  1. iCpu
                    15.01.2016 12:43
                    -3

                    Ну, возможно, потому, что она таковой и является? Да, я использовал неверный термин, объекты обмениваются сообщениями, но где в C++ сообщения, без Qt или бустовой магии, которую ещё собрать нужно?


                    1. AllexIn
                      15.01.2016 12:47
                      +7

                      class cA{
                      public:
                        foo();
                      };
                      
                      class cB{
                        cA* m_a;
                        bar(){
                          m_a->foo();
                        }
                      }
                      

                      Здесь есть обмен сообщениями, но нет слот-сигналов. Откуда вообще мысль, что обмен сообщениями привязан к слот-сигнальной системе и не может быть реализован другими методами?


                      1. iCpu
                        15.01.2016 12:48
                        -1

                        Броадкаст сообщение покажите?


                        1. AllexIn
                          15.01.2016 12:49
                          +6

                          Откуда мысль что бродкаст является обязательной частью ООП?


                          1. iCpu
                            15.01.2016 12:54
                            -5

                            Не является. Но, например, передача сообщений между потоками — является. Удачи с доказательством.


                            1. AllexIn
                              15.01.2016 12:55
                              +2

                              Брр. Вы сейчас говорите, что два потока на С++ не могут обмениваться сообщениями? :)


                              1. iCpu
                                15.01.2016 12:57
                                -1

                                Не в том виде, что вы указали.


                                1. AllexIn
                                  15.01.2016 13:11
                                  +4

                                  Так в том и фишка. Нет никаких требований к способу обмена. Обмен есть, остальное не имеет значения.


                                  1. iCpu
                                    15.01.2016 13:28
                                    +3

                                    Если так подходить к вопросу, вы правы. Но тогда не вижу причин не причислять да даже тот же чистый C к ООП языкам. При желании можно даже наследование сделать и много чего другого интересного сделать, года два назад были подобные статьи.

                                    Я очень уважаю ваше желание отстоять звание C++, но взгляните правде в глаза. Это не то ООП, которое создали вместе со SmallTalk.


                                    1. AllexIn
                                      15.01.2016 13:32
                                      +6

                                      Я не против других подходов к определению ООП. Но мне пока не понятно откуда вы берете свои доводы.
                                      Определенно C++ не SmallTalk. Но ему им быть и не надо.
                                      И на plain C можно эмулировать ООП. Также как на С++ можно эмулировать слот-сигнальную систему.

                                      Вы подняли сейчас верную тему. ООП — методология проектирования, я не свойство языка. Просто есть языки, на которых эта парадиграм реализуется просто, а есть те, на которых сложно. И всё.


                      1. Googolplex
                        15.01.2016 12:49
                        +3

                        Строго говоря, здесь нет обмена сообщениями. Здесь вызов функции, как в старом добром процедурном языке, просто выглядит иначе. Обмен сообщениями подразумевает, что та сторона, которой отправлено сообщение, сама решает, что делать с сообщением — например, может от него отказаться.


                        1. AllexIn
                          15.01.2016 12:51
                          +2

                          Получив сообщение через вызов метода объект может делать с ним все что захочет. Например, не обрабатывать.
                          Пожалуйста, укажите мне источник вашего мнения относительно сообщения применительно к ООП.
                          Я вот тут уж начал сомневаться, полез на википедию и там тоже не нашел ничего, что ставило бы к сообщениям в ООП обозначенные вами и iCpu требования.


                          1. iCpu
                            15.01.2016 12:55
                            +1

                            1. AllexIn
                              15.01.2016 12:55
                              +1

                              А этот тут при чем?


                              1. iCpu
                                15.01.2016 12:59

                                Ну, как, концепция «Сообщения» обязывает.


                            1. creker
                              15.01.2016 13:01
                              +2

                              Возьмем ObjC, канонический ООП язык. Отправителя автоматически не получить, броадкаст сообщений нет. Даже посылка сообщений максимально зарезана в пользу статического анализа, что выглядит уже как методы обычные.
                              А что до С++, передавайте отправителя аргументом.


                          1. Googolplex
                            15.01.2016 13:00
                            +2

                            en.wikipedia.org/wiki/Object-oriented_programming#Dynamic_dispatch.2Fmessage_passing

                            By definition, it is the responsibility of the object, not the external code, to 'on-demand' select the procedural code to run/execute in response to a method call, typically by looking up the method at run time in a table associated with the object.


                            В данном случае вызов метода ничем не отличается от вызова обычной функции, потому что метод, по сути, функция и есть. Понимаете, то, что управление передано в метод, уже означает, условно говоря, что объект «получил» «сообщение». Посмотрите, как ООП реализовано в Smalltalk, например — это именно то ООП, которое изначально подразумевалось под этим термином.

                            Однако, на самом деле, это действительно просто вопрос терминологии. То, что под терминами подразумевается, постоянно меняется, и то, что C++ и Java на протяжении всего их времени жизни называли ООП-языками, сместило/расширило суть понятия ООП. Поэтому называть ООП-языками C++, Java и прочие, на мой взгляд, вполне приемлемо. Например, та же штука произошла, хоть и более быстро, с термином RESTful. Что только под ним сейчас ни понимают, но в 99% случаев это даже близко не напоминает то, что изначально подразумевалось в исходной работе, где этот термин был введён.

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


                    1. Chaos_Optima
                      15.01.2016 12:52
                      +6

                      Эм… впервые слышу что сигналы слоты являются обязательной атрибутикой ООП. Всегда считал что язык поддерживает ООП если в нём есть полиморфизм, наследование и инкапсуляция.


                      1. Googolplex
                        15.01.2016 13:04
                        +1

                        Эти критерии не тождественны объектно-ориентированности. Например, в Go есть всё, что вы указали (окей, наследование с натяжкой), но он не является объектно-ориентированным. Когда в Rust добавят простое наследование структур (такие RFC уже есть), он тоже будет содержать все эти концепции, но он также не будет ОО.


                        1. bromzh
                          15.01.2016 13:18
                          +3

                          Да что там go, по таким критериям Haskell — один из самый Ъ ООП языков, там даже полиформизм круче!


                        1. creker
                          15.01.2016 13:48
                          +2

                          Опять эта тема. Является он объектно-ориентированным, потому что покрывает все его принципы. Это тоже самое, что smalltalk и С++. Последний не обязан быть SmallTalk, чтобы быть ООП языком. Тоже самое с Go — это другой язык, но инкапсуляцию, наследование и полиморфизм своими фичами он вполне покрывает. Именно в этом определение ООП языков и не надо тут выдумывать науку из этого целую.


                          1. Googolplex
                            15.01.2016 14:39
                            +3

                            Нет, определение ООП-языков не в этом.

                            Object-oriented programming (OOP) is a programming paradigm based on the concept of «objects», which are data structures that contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods.

                            Объектно-ориентированный язык так или иначе поощряет проектирование и программирование в терминах объектов и взаимодействия между ними. Если это не так, то язык не является объектно-ориентированным. Наличие полиморфизма (кстати, какого именно? Параметрического, ad-hoc, подтипов?), наследования и инкапсуляции не является ни необходимым, ни достаточным условием. Например, в Python инкапсуляция отсутствует в принципе — вы всегда можете добраться до чего угодно в любом объекте, но он от этого не становится менее объектно-ориентированным. И наоборот, ни Go, ни Rust не поощряют проектирование в ООП-терминах (объекты, классы, иерархии и прочее), поэтому они не являются ООП-языками.


                            1. creker
                              15.01.2016 14:52
                              +1

                              Еще как поощрается, только в своих терминах, которые тем не менее покрывают принципы ООП. Опять начинаются эти придирки к словам вместо того, чтобы смотреть на суть вещей. В Go есть объекты, есть интерфейсы, есть иерархии (да, немного не такие, к каким мы привыкли, те менее есть). Поощрается взаимодействие между ними. Более того, на нем никак иначе и писать невозможно.
                              Что до раста, то беглый просмотр в гугле приводит к выводу, что Rust мультипарадигменный язык, в том числе и объектно-ориентированный. Это просто не копия какого-то другого языка.


                              1. saboteur_kiev
                                15.01.2016 15:29
                                +3

                                Основной принцип ООП — это то, что мы работем не с функциями и данными, а с данными, заключенными в объект ВМЕСТЕ с методами, которые эти данные обрабатывают.

                                Таким образом объект представляет собой самодостаточный код, в который может залезть программист, и фиксить, а не бегать по 100500 тысяч файлов в поисках всех связанных сущностей.

                                Все остальные штуки — наследования, полиморфизмы — это попытки сделать объекты более удобными, но основная суть — выше.


                                1. bromzh
                                  15.01.2016 18:38
                                  +1

                                  Основной принцип ООП — это то, что мы работем не с функциями и данными, а с данными, заключенными в объект ВМЕСТЕ с методами

                                  Ну тогда ООП в лиспе и не ООП совсем.
                                  Там мы работаем с функциями, только обобщёнными. И отдельно от них определяются данные — с помощью классов.

                                  Оттого там, например, и диспетчеризация может быть более чем по 1-му параметру.


                                1. creker
                                  15.01.2016 21:26
                                  +1

                                  Основной принцип ООП — это то, что мы работем не с функциями и данными, а с данными, заключенными в объект ВМЕСТЕ с методами, которые эти данные обрабатывают.

                                  Ну тогда все еще проще. Go прям православный ООП язык.


                            1. bromzh
                              15.01.2016 22:47
                              +1

                              Например, в Python инкапсуляция отсутствует в принципе

                              Её «можно» организовать с помощью замыканий. Ну т.е. получить значение станет немного труднее. Потому что, видимо, в любом языке так или иначе можно-таки добраться до private- или спрятанных в замыкание значений.


                            1. MacIn
                              16.01.2016 15:54
                              +1

                              Нет, определение ООП-языков не в этом.

                              В цитате — как раз об инкапсуляции. GO через расширение структур это делает.

                              Если обратиться за определением к википедии, мы обнаружим 2 понимания термина «инкапсуляция»:
                              In programming languages, encapsulation is used to refer to one of two related but distinct notions, and sometimes to the combination[1][2] thereof:

                              A language mechanism for restricting access to some of the object's components.[3][4]
                              A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.[5][6]


                              В русскоязычной литературе и ВУЗах принято второе, выделенное жирным.



          1. gurinderu
            15.01.2016 13:44
            +1

            Я где-то ниже дал ссылку на ooc. Почитайте.
            Никто вам не мешает писать на C в oo-style.

            А еще лучше сразу гляньте GTK. Там все объектное, хотя чистый C.


          1. R10
            17.01.2016 17:27
            +1

            Программирование без ООП, даже больше — почему с ООП нельзя достичь high performance: www.dataorienteddesign.com/dodmain


        1. bromzh
          15.01.2016 12:08
          +2

          А разве из динамической либы, собранной из C++ можно дёргать классы через ffi? Там вроде как проблема была с виртуальными методами. В команде KDE специально писали libsmoke, чтобы можно было легко делать биндинги для других языков. В случае C всё было бы проще: дёргай ffi и всё.
          Или сейчас уже нет проблем с динамическими либами на c++? А то я давно уже не писал на с++.


        1. dordzhiev
          15.01.2016 23:04
          +1

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

          Развивая вашу мысль, и POSIX, и WinAPI также имеют C-интерфейс снаружи. Теперь все приложения на C писать? Нет, спасибо, я уже даже без буста не могу, не говоря уже о том чтобы к vanilla С вернуться.


    1. saboteur_kiev
      15.01.2016 12:10
      +1

      Например, на хороший ИИ?

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

      в крупных MMO, на сервер тоже может падать нагрузка, просчитывать поведение сотен тысяч MOBов.


      1. k12th
        15.01.2016 12:21
        +1

        Ну если только. Обычно все-таки задачу «предоставить игроку сильного интересного противника» предоставляют мультиплееру, а не пишут мегасложный ИИ для босса.


        1. saboteur_kiev
          15.01.2016 12:44
          +1

          А причем тут мегабосс?
          Обслуживание активного живого мира — сложная задача, поэтому большинство на нее забивает.

          Это же вторая часть 3D, в котором не только «можно ли отсюда увидеть объект», но и «как отсюда пройти к нему, не застряв в текстурах», повторить для пары сотен объектов. Обычно делают уже готовые предрасчитанные пути. Из-за чего кардинальное изменение мира — не везде работает. Майнкрафт обошелся крупными кубиками и простейшим ИИ, а мог бы…


  1. Nanako
    15.01.2016 01:15
    +4

    Немного странные рассуждения. Я, например, пишу в основном на C#, на C++ и C периодически, и портирую кучу всего из одного в другой. Дак вот для меня дико сложный C, нормальный C++ и совсем легкий C#. Ну в смысле, работы с сокетами и системой, многопоточностью, IPC и все такое. И код читать проще, и вообще все как-то тупее в реализации получается. Производительность наверное да, страдает. Но не так чтобы ужас ужас.


  1. PapaBubaDiop
    15.01.2016 01:58
    +10

    Крик души понятен.
    Все родное, удобное и вдобавок быстро компилируется.
    Замечу, что Турбо-Паскаль в 5 раз быстрее компилировался, чем Турбо-С.
    Да.
    Но всё равно его пришлось бросить.


    1. dea
      15.01.2016 16:04
      +2

      Насчет пяти раз это вы поскромничали, кмк.


  1. 1vanK
    15.01.2016 04:49
    +16

    Такие игры, что на сайте у автора, хоть на асемблере пиши


  1. bromzh
    15.01.2016 05:02
    +3

    Почему-то не упомянут Lua. А ведь можно взять SDL и lua-jit, в котором есть FFI. Весь код можно писать на lua, дёргая нужное из SDL через этот FFI. Ну и ещё всякие массивы объявлять как c-переменные (а то таблицы луа скоростью не блещут).
    По скорости код будет немного уступать решению на С, зато (имхо) писать приятнее…


    1. justaguest
      15.01.2016 06:45
      +1

      Ну тогда лучше сразу Haskell взять — богатая система типов, краткость, удобство… Но автор уже выкинул Go — потому что сборщик мусора.


      1. bromzh
        15.01.2016 07:11
        +2

        Луа — небольшой простой язык, его интерпретатор довольно маленький, встраивается куда угодно и его можно уместить в APK.
        Не знаю про хаскель, но разве там не требуется слинковать все хаскелевские модули статически, чтобы получить standalone-приложение? И соберётся ли всё это под нужную архитектуру? Скомпилить и запустить хаскелевскую программу можно, но судя по ответам на SO — это тот ещё гемморой.

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


        1. justaguest
          15.01.2016 07:42
          +1

          Стоп, мы ведь говорим о платформах с сишными библиотеками, как SDL? Да, соберется. И да, компиляция статическая, т.к. происходит проверка типов по всем модулям. Ну, а Lua не статически типизирован, и хотя, наверное, изредка это удобно — например, как вы выразились, подправить что-то на конечном дейвасе — в разработке от этого больше проблем. Чем больше проект, тем сложнее писать на динамическом языке, именно потому что все проблемы всплывают на конечном девайсе, куда это все еще надо загрузить и запустить ;)

          Как пример таких проблем могу вспомнить питоновский PyUNO — объективно, это не вина языка, просто это самое отвратительное АПИ какое я когда-либо встречал. Штука в том, что половина его проблем исчезла бы, если бы АПИ было на статическом языке.


          1. bromzh
            15.01.2016 08:03
            +1

            И да, компиляция статическая, т.к. происходит проверка типов по всем модулям.

            Я имел ввиду линковку. Т.е. если я использую какой-то модуль, мне его нужно слинковать статически с итоговым бинарником. Не выйдет ли так, что в итоге будет тяжёлый бинарник с большим рантаймом?

            На счёт того, что лучше, не буду спорить, всё равно каждый останется при своём мнении. Я лишь высказал свои идеи, которые меня как-то посетили.


            1. justaguest
              15.01.2016 08:23
              +2

              Я не использовал, но Haskell.org говорит, что можно.


    1. bromzh
      15.01.2016 06:55
      +1

      Кстати, ведь SDL портирован под кучу платформ. LuaJIT написана на сях и тоже работает почти везде. И это навело меня как-то на безумную мысль, что на такой связке можно писать простенькие и при этом довольно шустрые игры почти для всех популярных платформ (кроме веба).

      Ведь чтобы запустить программу, написанную вышеизложенным способом, достаточно запустить в интерпретаторе луа наш скрипт. На десктопных ОС всё обирается и запускается легко. На мобильных платформах провернуть всё это труднее, но вполне возможно: взять заранее собранные для нужной платформы динамическую либу SDL и интерпретатор луа, взять скрипты с другими ресурсами (звук, видео, картинки), написать простенькую запускалку всего этого и запаковать всё.

      Получится что-то типа LOVE (кстати, он теперь использует LuaJIT по-умолчанию), но проще.


      1. grossws
        15.01.2016 13:46
        +1

        кроме веба
        emscripten, и можно и для веба ,))


  1. 0x3f00
    15.01.2016 07:04
    +7

    Одно слово, почему я не буду писать на ванилла-С.
    Деструкторы.


    1. naryl
      15.01.2016 07:35
      +37

      Всё в порядке, в C нет деструкторов. Можете спокойно на нём писать. :)


      1. ForNeVeR
        15.01.2016 08:21
        +9

        Может, товарищу выше, наоборот, хочется деструкторов?


        1. beeruser
          15.01.2016 19:03
          +5

          Ох уж эти деструктивные наклонности.


    1. gurinderu
      15.01.2016 10:54

      Вам стоит почитать ooc. https://www.cs.rit.edu/~ats/books/ooc.pdf


      1. dordzhiev
        15.01.2016 23:09
        +2

        Но что толку от этого без RAII?


  1. AllexIn
    15.01.2016 07:50
    -1

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

    ООП — это не серебряная пуля. Но, если код пишет человек без ООП головного мозга, то код получается нагляднее и чище, чем на plain C. Я уверен, что при прочих равных код игры на С++ будет проще и нагляднее.

    Мне непонятен наезд на С++ про скорость компиляции. Современные процессоры и инкрементальная компиляция сделали компиляцию на С++ достаточно быстрой. Если же этого не хватает, то можно поместить исходники проекта на RAM диск и компиляция станет практически мгновенной.
    ИМХО автор пишет огромные портянки в каждом CPP, пихает реализацию в H и в итоге, конечно, в медленной компиляции виноват С++.

    P.S.
    Я то вообще Delphi люблю. Но С++ стал стандартом игростроения не просто так.


    1. slonopotamus
      15.01.2016 09:56
      +8

      C++ отвратительно медленно компилируется, вы легко можете в этом убедиться попробовав скомпилировать любой крупный C++-проект (OpenOffice, Chromium, UE4, kdelibs). Потому что в процессе происходит дублирование тонны информации в .obj-файлах. Вполне типична ситуация, когда .obj-файлы суммарно занимают, скажем, x100 места по сравнению с результирующим бинарником.


      1. alexeibs
        15.01.2016 10:17
        +2

        Ну так каков размер исходников Chromium'а? Клонирование всего дерева репозиториев запросто может быть медленнее, чем непосредственно сборка.


        1. SHVV
          15.01.2016 10:34
          +4

          Ну например у нас тоже большой проект.
          Экспорт кода из репозитория занимает несколько минут, а сборка всего проекта половину дня.
          И при этом 8-ми ядерный i7 (4 реальных + 4 виртуальных) загружен на 100%.
          То есть даже не в диск упирается.


      1. AllexIn
        15.01.2016 11:10
        +2

        Когда мне нужен ребилд — я просто ставлю его на ночь. А в процессе работы инкрементальная сборка сводит компиляцию к секундам.


        1. slonopotamus
          15.01.2016 11:14
          +10

          Когда мне нужен ребилд — я просто ставлю его на ночь.


          Ну в общем-то предлагаю на этом закончить, вы и сами признали, что C++ медленно компилируется.


          1. AllexIn
            15.01.2016 11:16
            +3

            Не надо демагогии.
            Ребилд не является основной операцией в процессе разработки и скорость его не имеет принципиального значения.


            1. slonopotamus
              15.01.2016 11:21
              +8

              Я хочу чтобы проект билдился в пределах единиц минут вне зависимости от того, какой файл понадобилось поменять. В противном случае, могут возникать всякие нездоровые мысли типа «не буду рефакторить этот кривой метод, потому что придётся поменять сигнатуру в H-файле и получить пересборку на два часа».


              1. AllexIn
                15.01.2016 11:31
                +2

                Давайте меньште абстрактных «два часа» и больше конкретики:
                store.steampowered.com/app/380770 сессионная ММО на С++
                Исходники одного только движка 16 мегабайт. Плюс еще столько же сама игра. Ребилд в 2015 году — около 10 минут.

                store.steampowered.com/app/11560 РТС c терраформингом
                Я не помню сколько там весили исходники. Использовался IncrediBuild. В 2006 году полный ребилд занимал меньше 30 минут.

                Уж простите, но игры автора даже при полной пересборке всего врядли больше минуты компилятся.


                1. gwer
                  15.01.2016 11:34

                  Автора сборка дольше 10 секунд уже заставляет грустить.


                  1. AllexIn
                    15.01.2016 11:35
                    +1

                    Так сборка же, а не ребилд.


        1. SHVV
          15.01.2016 11:38
          +5

          Когда мне нужен ребилд — я просто ставлю его на ночь.

          А утром прийти и увидеть, что за ночь ничего не скомпилировалось, потому что таки допустил ошибку в коде. И всё, ещё один день впустую!
          P.S. Я тут сижу просто потому, что у меня всё ещё компилируется. ;-)


          1. AllexIn
            15.01.2016 11:50
            +3

            Ошибку в интерфейса допустить сложнее чем в реализации. Да и компиляция прервется в самом начале, ведь если мы меняли хидер, то именно он будет скомпилирован первым и только потом «тысячи» файлов зависимостей от него.
            Ну а изменение кода в CPP не приведет к перекомпиляции проекта.
            Так что не принимается.


            1. SHVV
              15.01.2016 13:43
              +1

              Да, обычно так и бывает, но не всегда.
              Например во время рефакторинга, когда затрагивается несколько библиотек. К счастью, это редкость.
              В любом случае, это не отменяет того факта, что компилятор С++ один из самых медленных по сравнению с другими популярными языками.


          1. 0xd34df00d
            15.01.2016 15:11
            +1

            Вероятнее всего, как уже ниже написано, либо сразу увидите, не успев встать из-за машины, либо проблема в паре .cpp-файлов, и тогда make -k вас спасёт.


        1. saboteur_kiev
          16.01.2016 03:38
          +1

          У вас просто маленький проект.
          Мы пишем ОС, и компиляция с нуля идет около 8 часов на хорошем рабочем компе.
          При помощи всяких ухищрений, icecc, sstate и др, добились около 2-3 часов.
          Даже до 25 минут на компе с 32 ядрами и 128 гб оперативки.
          Но до секунд не добраться никак. 80% времени — компиляция, 20% — дисковая подсистема.


          1. AllexIn
            16.01.2016 10:37
            +2

            Во-первых — при чем тут ОС? Речь о разработке игр.
            Во-вторых я уже приводил пару примеров проектов в которых работал программистом, я бы не назвал их маленькими. :)
            В-третьих — имеет смысл анализировать не ваши или мои проекты, а проекта автора.


    1. slonopotamus
      15.01.2016 10:03
      +3

      пихает реализацию в H


      C++ заставляет пихать реализацию темплейтов в H. И заставляет пихать объявления private-методов. При чем здесь автор, это язык такой.


      1. AllexIn
        15.01.2016 11:12

        И много шаблонов вам надо в геймдеве?
        Я работал над несколькими действительно большими проектами и шаблоны встречал только на самом низком уровне движка. Они были раз реализованы и никогда не менялись.

        Отдельно интересно, как автор решает проблему шаблонов в хидере в своих играх на plain C.


        1. Chaos_Optima
          15.01.2016 11:22
          +3

          Отдельно интересно, как автор решает проблему шаблонов в хидере в своих играх на plain C.

          Наверно никак, потому что в С нет шаблонов.


          1. AllexIn
            15.01.2016 11:23
            +4

            О чем и речь.
            Отказываться от С++ потому что он медленно билдит шаблоны в пользу С на котором шаблонов нет вообще…


            1. Chaos_Optima
              15.01.2016 11:29
              +5

              Я лично тоже не вижу причин отказываться от С++ в пользу С, одних деструкторов достаточно чтобы забыть про С и влюбится в С++.


              1. 0x3f00
                15.01.2016 13:28
                +2

                Вот!


        1. slonopotamus
          15.01.2016 11:29

          Отдельно интересно, как автор решает проблему шаблонов в хидере в своих играх на plain C.


          В plain C нет проблемы шаблонов. Ну и вы как-то ловко проигнорировали вторую часть, про объявления private-методов в заголовках, проблемы с которыми в plain C кстати тоже нет.


          1. AllexIn
            15.01.2016 11:32
            +5

            Намека на шаблоны не достаточно?
            Ладно, я намекну и на private: и как же автор решает проблему объявления приватных методов в plain C? :)


            1. gwer
              15.01.2016 11:38
              +1

              Не надо ООП тащить в pure vanilla C, и проблем не будет. Функция изначально приватная, если не сказано об обратном (extern).


              1. xaizek
                15.01.2016 12:17
                +1

                Функция изначально приватная, если не сказано об обратном (extern).
                Только с точностью наоборот (внешняя линковка по умолчанию, если не указано static), а extern для того, что объявлено «не здесь».


                1. gwer
                  15.01.2016 12:23

                  Да, что-то к пятнице мозги набекрень)


              1. JIghtuse
                15.01.2016 12:39
                +1

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

                xaizek опередил.


            1. bromzh
              15.01.2016 11:41
              +1

              Может как в питоне, т.е. никак? Ответственность с разраба библиотеки переложить на плечи программиста, который её использует. Можно договориться о наименовании и вызывать «скрытые» методы только на свой страх и риск.

              Так-то, private — тот ещё костыль, т.к. к нему при должном умении всё равно можно достучаться.


    1. MacIn
      16.01.2016 16:04
      -2

      Если же этого не хватает, то можно поместить исходники проекта на RAM диск и компиляция станет практически мгновенной.

      Ох ты ж… последний раз приходилось применять этот трюк, когда работал в 90х на 286 процессоре с 4 Мб памяти и 40 мегабайтным MFM диском. Компилятор Fortran а производства MS был дико медленен по сравнению с другими платформами. Только RAM диск и спасал.

      А гляди ж ты — опять такой трюк работать будет.

      Мда, как же здорово, что у нас проекты на Delphi с полным ребилдом собираются за 15-20 секунд. Миллионы строк.


      1. AllexIn
        16.01.2016 16:09
        +2

        Я RAM диск использовал для С++ проектов лет 6 назад последний раз.
        С тех пор я открыл для себя инкрементальную компиляцию и перестал извращаться с RAM дисками.


    1. vladon
      18.01.2016 15:04
      +4

      Да, С++ сложнее С.


      Как по мне, так наоборот.

      Он настолько сложен, что ни один(или все такие есть такой?) компилятор не поддерживает его стандарт полностью.


      В clang полностью реализован весь стандарт C++14. В gcc, вроде бы, тоже, не слежу за ним. И даже MSVC почти догнал.
      А вот как раз C11 не реализован нигде целиком.

      Например, я пишу на С++ игры, но я некоторые возможности С++ не знаю и не изучаю. Например, я почти не ориентируюсь в шаблонах и без документации не смогу написать даже простого. Просто потому, что шаблоны практически не применяются при программировании игр.


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

      А насчёт скорости: в C++17 появятся модули, и тогда по скорости компилирования C++ догонит Паскаль (Дельфи).


      1. AllexIn
        18.01.2016 15:12
        +1

        Это именно вы их не применяете безотносительно области вашей разработки.

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

        Опять ошибочная догадка. К примеру, писал Тулкиты и активно в них использовал шаблоны, например, для property.
        В игра на высоком уровне шаблоны просто не нужны.


        1. 0xd34df00d
          18.01.2016 15:19
          +2

          В игра на высоком уровне шаблоны просто не нужны.

          Почему? Например, легко допустить возможность ситуаций, когда возможно рантайм-полиморфизм (виртуальные функции, это всё) заменить на статический полиморфизм (boost.variant, это всё). Профитом получаем повышенную типобезопасность и быстродействие.


        1. vladon
          18.01.2016 15:20
          +1

          Шаблоны — это просто техника программирования, обобщённые алгоритмы.

          Я даже навскидку сейчас придумаю с ходу, зачем могут понадобиться: есть N типов спрайтов и есть единый алгоритм для их обработки, например.

          А почему не используются, тоже можно объяснить: обычно в таких проектах есть некий гуру-старпёр, который их просто не понимает и не хочет понимать. Однажды на одном из собеседований я не прошёл, потому что использовал лямбды, цитата: «незачем использовать эту новомодную лапшу из новых стандартов, и вообще новые стандарты не нужны».


          1. AllexIn
            18.01.2016 15:21
            +1

            Пример слишком абстрактный. Давайте конкретнее.


            1. vladon
              18.01.2016 15:27
              +1

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


              1. AllexIn
                18.01.2016 15:30
                +1

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


                1. vladon
                  18.01.2016 15:33
                  +1

                  Так это вы просто не понимаете, с этого и надо было начинать :-)

                  Это просто два способа решить одну и ту же задачу. Каждый выбирает себе по вкусу. Вижу минусы и плюсы и у того и у другого варианта.


                  1. AllexIn
                    18.01.2016 15:48
                    +1

                    Конечно я этого не понимаю. Если бы я понимал преимущества шаблонов в конкретной этой ситуации, я бы не говорил что они не нужны.

                    По всему получается, что вы эти преимущества понимаете и сможете объяснить.


                    1. vladon
                      18.01.2016 15:56
                      +3

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

                      Например, с теми же спрайтами. Есть общий класс Sprite. Есть наследуемые, например: Dragon, Knight и Princess (: public Sprite).

                      Наложение для всех сочетаний одинаковое. Реализуйте общий алгоритм наложения своим способом (ну, можно это сделать методом в Sprite).

                      А теперь специализируйте это наложение именно для наложения Knight на Dragon, допустим, а в остальном оставьте то же самое.


                      1. AllexIn
                        18.01.2016 15:58
                        +1

                        То есть для того чтобы сделать уникальную обработку для Knight/Dragon мы должны менять код в базовом шаблоне? Или я не правильно понял?


                        1. 0xd34df00d
                          18.01.2016 16:00
                          +3

                          Можно сделать специализацию.


                        1. vladon
                          18.01.2016 16:02
                          +4

                          Как раз нет. Можно либо сделать template overloading, либо template specialization. Гуглите.

                          Если без шаблонов вы это будете специализировать, скорее всего, в конкретном классе (оверрайдом виртуальной функции), т.е. код может быть разбросан по куче разных файлов, то при использовании шаблонов всё будет рядышком. Красиво, чисто, удобно, а самое главное — нет грязи (возможных проблем) с указателями. И можно не делать виртуальную функцию (что накладывает, конечно же, свою печать на производительность).


                      1. Nanako
                        18.01.2016 16:12
                        +1

                        По моему пример не очень. Тут лучше коллекции подойдут. Например у вас есть классы наследованные от «спрайта», есть классы наследованные от «звука», есть классы наследованные от «ресурса». И вам нужен мультиплеер или для ИИ нужно контролировать какие звуки и спрайты кто имеет чтобы рассчитать кто кого видит/слышит или передачу чего-то по сети, например. И вместо того чтобы устраивать множественное наследование всего от одного класса или городить интерфейсы вы делаете темплейт обертку/коллекцию которая помечает что кому принадлежит и может это все индексировать и хранить с хэшем. И потом создаете для звуков Обертка<Звук>, для спрайтов Обертка<Спрайт> в коде, и у вас одна имплементация «контроля принадлежности» вне зависимости от того объекты какого класса вы решили контролировать.


                        1. vladon
                          18.01.2016 16:14
                          +1

                          Я пытался упростить уж. И показать, что даже на примере одного вида объектов (тупо спрайтов) шаблоны очень помогают. Чего уж говорить о взаимодействии кучи разных иерархий.


                          1. Nanako
                            18.01.2016 16:18
                            +1

                            Ну шаблоны в простых ситуациях слабо помогают, зато сегодня у меня вот такой кадавр родился:

                                public sealed class MarketDataStream<T,X,Y> : IDisposable, ILoggerAttached, INamed 
                                    where X: IStreamHeader 
                                    where Y: IStreamFeedbackHeader
                            


                            1. vladon
                              18.01.2016 16:20
                              +1

                              Это же не C++.


                              1. Nanako
                                18.01.2016 16:32
                                +1

                                А какая разница, я могу ошибаться, но можно так:

                                template <class T, IStreamHeader X, IStreamFeedbackHeader Y>
                                class MarketDataStream : public IDisposable, public ILoggerAttached, public INamed { }
                                

                                Я не так хорошо знаю С++ правда, если есть ошибки, скажите, мне самому интересно


                                1. vladon
                                  18.01.2016 16:38
                                  +1

                                  Так делать нельзя (явно передавать типы в параметрах шаблона), non-typed parameters могут быть только int'ы и т.п.


                                  1. Nanako
                                    18.01.2016 16:48
                                    +1

                                    Бида, бида. Вобщем слава богу я всякий UI на C# пишу. На С++ у меня только обертки всякого хардкора и порты С библиотек.


                                1. 0xd34df00d
                                  18.01.2016 16:39
                                  +1

                                  Подойдёт только в том случае, если IStreamHeader или IStreamFeedbackHeader — типы вроде enum. Требование к наследованию от интерфейса (что, насколько я знаю, представляет where в C#-коде) так выражать не получится, для этого нужны либо концепты из C++17, либо всякие std::enable_if + std::is_base_of.


                                  1. Nanako
                                    18.01.2016 16:46
                                    +1

                                    Ясно, это я еще помню как override в С++ раньше не было, тоже удивлен был.
                                    IStreamHeader и IStreamFeedbackHeader интерфейсы struct, т.е. в С++ тоже не получится?


                                    1. vladon
                                      18.01.2016 16:50
                                      +1

                                      В C++ struct и class — одно и то же, нюансы в видимости по дефолту.

                                      Я так понял, вам нужно, чтобы был передан объект, который реализует определённый интерфейс?
                                      Два варианта: как сказал выше 0xd34df00d, либо просто передавать их в конструктор (а смысл шаблониться от конкретных объектов? Эдак у вас на каждый объект будет разворачиваться шаблон, отсюда и требование.)


                                      1. Nanako
                                        18.01.2016 16:56
                                        +1

                                        Ну там чуть посложнее, там передается поток данных, а в начале memorymap два заголовка, чтобы не локать треды. Передатчик и приемник знают какие структуры они пишут, а обертке потока нужно только пара параметров которые есть во всех заголовках. В итоге все структуры заголовков унаследованы от

                                            public interface IStreamHeader
                                            {
                                                Guid Tag { get; set; }
                                                long Size { get; set; }
                                                long Heartbeat { get; set; }
                                                int DataOffset { get; set; }
                                                bool Choked { get; set; }
                                            }
                                        

                                        Размер структуры в заголовке чтобы считать смещение следующей, ну и т.д. В итоге указание интерфейса структур в шаблоне это просто страховка, можно и не указывать на самом деле.


                                        1. vladon
                                          18.01.2016 16:59
                                          +1

                                          Так в C++ делайте в конструкторе, помимо того что невозможно — ещё и незачем указывать их как параметры шаблона.


                                    1. vladon
                                      18.01.2016 16:52
                                      +1

                                      Т.е. вам надо:

                                      template <class T>
                                      class MarketDataStream : public IDisposable, public ILoggerAttached, public INamed 
                                      {
                                          // конструктор 
                                          MarketDataStream(IStreamHeader X, IStreamFeedbackHeader Y)
                                          {
                                              // ... 
                                          }
                                      }
                                      


                                    1. vladon
                                      18.01.2016 16:53
                                      +1

                                      Ясно, это я еще помню как override в С++ раньше не было, тоже удивлен был.


                                      оверрайдить-то всегда можно было, просто не было явного ключевого слова.


                                      1. Nanako
                                        18.01.2016 17:07
                                        +1

                                        Ну в C# и Java указывать override это mandatory. Я в смысле что ООП в С++ оно вольное какое-то. Я до сих пор в восторге от Питона, правда не пишу на нем сейчас практически.


                                        1. vladon
                                          18.01.2016 17:09
                                          +1

                                          Ну не сравнивайте язык, в котором ООП был спроектирован изначально (C#) гением (создателем Delphi) и где, в принципе, иногда забивают на обратную совместимость (это правильно, кстати), с языком, в котором вынуждены обеспечивать обратную совместимость из-за тех, кого я называю гуру-старпёрами.


          1. 0xd34df00d
            18.01.2016 15:22
            +5

            Однажды на одном из собеседований я не прошёл, потому что использовал лямбды, цитата: «незачем использовать эту новомодную лапшу из новых стандартов, и вообще новые стандарты не нужны».

            Я в таких случаях всегда радуюсь, что наша взаимная несовместимость с потенциальной командой открылась так рано.


      1. 0xd34df00d
        18.01.2016 15:21
        +1

        В gcc, вроде бы, тоже, не слежу за ним.

        Формально реализован, по факту встречаются баги сильно чаще, чем в clang. Причём, чаще это мешающие баги — clang скорее акцептит невалидный код, тогда как gcc реджектит валидный.

        А насчёт скорости: в C++17 появятся модули

        Как у них там с экспортом темплейтов из модулей, кстати?


        1. vladon
          18.01.2016 15:24
          +1

          Формально реализован, по факту встречаются баги сильно чаще, чем в clang. Причём, чаще это мешающие баги — clang скорее акцептит невалидный код, тогда как gcc реджектит валидный.


          Не знаю, мне gcc не нравится по скорости компиляции, да и в clang аналитики больше, те же санитайзеры чего стоят. Кстати, есть пример акцепта clang'ом невалидного кода?

          Как у них там с экспортом темплейтов из модулей, кстати?


          Я не слежу, в clang пока не появилось.


          1. 0xd34df00d
            18.01.2016 15:28
            +1

            Не знаю, мне gcc не нравится по скорости компиляции, да и в clang аналитики больше, те же санитайзеры чего стоят.

            Аналогично.

            Кстати, есть пример акцепта clang'ом невалидного кода?

            Например. Кстати, блин, так и не обновил.

            Я не слежу, в clang пока не появилось.

            Я какой-то то ли пропозал, то ли обсуждение читал, и там как-то всё плохо с темплейтами.


            1. vladon
              18.01.2016 15:58
              +1

              Я какой-то то ли пропозал, то ли обсуждение читал, и там как-то всё плохо с темплейтами.


              Фиг его знает, что будет, но одним из недостатков include'ов авторы разных пропозалов о модулях заявляют как раз неудобство реализации шаблонов в инклюдах. Вчитываться вообще нет времени…


  1. SHVV
    15.01.2016 08:56
    +6

    Кармак тоже раньше писал свои движки на C. Но начиная с третьего Дума таки перешёл на С++. Итересно почему?


    1. jia3ep
      15.01.2016 10:20
      +3

      Может быть потому, что для написания третьего Дума пришлось набирать много новых разработчиков, а программистов на C искать все сложнее с каждым годом.

      Хорошо еще на C++, а то сейчас в резюме чаще указывается знание неизвестного мне языка C/C++, а вот знание C или C++ теперь встречается все реже.


      1. AllexIn
        15.01.2016 11:13
        +5

        Сфера применения знака / (косая черта) — научная и деловая речь. Он употребляется в следующих функциях.
        1. В функции, близкой к союзам и и или, как знак альтернативности понятий или обозначения единого сложного понятия.


        1. jia3ep
          15.01.2016 11:32
          +5

          Это неприменимо при указании названия языков. Например, язык C++/CLI является отдельным языком и имеет свой стандарт — ECMA-372.

          И вообще, это была шутка на тему того, что множество людей, которые указывают в резюме C/C++, не тождественно множеству людей, которые знают C и C++ одновременно.


          1. AllexIn
            15.01.2016 11:35
            +1

            Это неприменимо при указании названия языков.

            Почему? Я бы с вами согласился, если бы был язык C/C++, но него нет. Так что нет противопоказаний для такого употребления.


            1. xaizek
              15.01.2016 12:34
              +2

              Согласно Вашему же комментарию выше, C/C++ следует трактовать одним из следующих способов:

              • C и C++
              • C или C++
              Теперь посмотрите на оба и подумайте об их применимости. Если это вакансия или резюме, то знание «C или C++» звучит как минимум бредово, но скорее абсолютно некорректно. С вариантом «C и C++» другая проблема, на удивление мало людей действительно знает их как два самостоятельных языка: знающие C зачастую не знают практически ничего из C++, знающие C++ (по моему опыту) думают, что в C есть ссылки, нету typedef, без понятия о функциях вроде strspn(), не знают отличий приведения типов и т.д.

              Т.е. приходим к выводу, что применимость обозначения «C/C++» настолько узкая, что оно практически всегда применяется неправильно. А если ещё и учесть двоякость трактовки («и» или «или»), то смысл использования такой записи вообще теряется, так как не понятно, что хотели сказать.


              1. AllexIn
                15.01.2016 12:36
                +2

                Я С/C++ всегда воспринимаю так: я пишу на С++ и знаю чем он отличается от С.


                1. xaizek
                  15.01.2016 12:39
                  +6

                  Первый раз втречаю такую трактовку и не сказал бы, что мог бы предположить её существование. Для меня это лишний раз показывает ошибочность практики применения записи «C/C++».


                  1. DSL88
                    15.01.2016 15:25
                    +1

                    А я просто пишу: С, С++
                    =)


      1. 0xd34df00d
        15.01.2016 15:12

        А мне и язык C++ неизвестен. Надо указывать точно C++03 либо 11 либо 14!


        1. jia3ep
          15.01.2016 15:29
          +1

          Язык все-таки C++. А вы говорите уже про разные версии стандарта. Например, ISO/IEC 14882:2011(E) — это стандарт языка C++, который определяет, что «C++ is a general purpose programming language». Тоже самое написано и в других версиях стандарта.


          1. 0xd34df00d
            15.01.2016 16:41
            +4

            Однако, идиомы и подходы к написанию кода на C++03 и C++11 существенно отличаются. После изучения C++03 необходимо потратить значительное количество времени, чтобы начать писать на «правильном» C++11. Знание C++03 не означает знание C++11.

            Да и с практической точки зрения, действительно, если я беру человека в проект, то мне надо знать, C++ какой именно версии он знает. Между 03 и 11 разница таки побольше, чем между 98 и 03, где это было несущественно.


            1. jia3ep
              15.01.2016 19:05
              +1

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


    1. sborisov
      15.01.2016 11:14
      +9

      www.linux.org.ru/forum/talks/8720321
      Как сообщает похороникс, Джон Кармак высказал своё окончательное мнение о противостоянии C и C++. Для обделённых знанием английского или пониманием божественности плюсов перевожу:

      Я до сих пор считаю код Quake 3 более чистым — в известном смысле. Это венец эволюции моего стиля на C, и одновременно первая итерация моего стиля на C++. Но такое отношение может быть вызвано меньшим количеством строк или тем фактом, что я не особо-то и не заглядывал туда уже десять лет. Я думаю, что «хороший C++» лучше, чем «хороший C» с точки зрения читаемости, а всё остальное эквивалентно.

      Я, конечно, поизвращался над C++ в Doom 3 — ведь я был опытным C-шным программистом с некоторым знанием ООП, пришедшим из Objective-C времён NeXT, так что я просто начал писать на C++ без нормального изучения юзкейзов и идиом. Вспоминая прошлое, я очень жалею, что не прочитал Effective C++ и некоторые другие книги. Часть остальной команды в прошлом имела опыт работы с C++, но они в целом следовали моим стилистическим решениям.

      В течение многих лет я не доверял обобщённому программированию, и все ещё применяю шаблоны с опаской, но в итоге я решил, что удовольствие от статической типизации перевешивает нежелание иметь раздутый код в заголовках. В Id Software всё ещё идут споры об использовании STL, и со временем они становятся жарче. Если же вернуться снова к временам, когда началась разработка Doom 3, призыв использовать STL тогда стал бы неудачной затеей, но сегодня в пользу этого решения уже есть серьёзные аргументы, в том числе в геймдеве.

      Также я теперь стал const-нацистом, и даю по рукам программисту, который не ставит const подходящим для этого переменным и параметрам.

      Главным нововведением, интересным для меня, является функциональное программирование — оно позволяет избавиться от многих старых привычек и вновь отказаться от некоторых идей ООП.


      1. justaguest
        15.01.2016 13:01
        +1

        Кстати по поводу const — любопытный факт, но далеко не всегда в ситуациях при оптимизации, где, казалось бы, компилятор должен догадаться о неизменяемости, он действительно догадывается. Помню, пол-года назад мне надо было оптимизировать прогу под встраиваемое устройство. Можно было переписать часть функций, превратив их в трудноотлаживаемую мешанину, но по опыту в будущем ни к чему хорошему это бы не привело. Поэтому — помимо игр с опциями оптимизаций компилятора — огромная часть проделанной работы оказалась простым путешествием по всем замешанным функциям кода, и заменой переменных и аргументов на const везде, где только можно. Работала такая оптимизация прежде всего со всякими векторами и структурами. Для проверки, сработало ли в очередной раз, достаточно перекомпилировать один объектный файл с оптимизациями — и, если размер уменьшился, следовательно компилятор смог применить еще какую-то оптимизацию.


        1. burjui
          15.01.2016 17:26
          +2

          Может, и так, но «const-нацизм» используется в первую очередь для того, чтобы оградить себя от случайной модификации данных (будь то аргументы или локальные переменные), и уже во вторую очередь — для оптимизации. D C++ это работает так себе, поэтому в D пошли ещё дальше, и сделали const транзитивным:

          void fn(const int *x)
          {
              int y;
              x = &y; // error
              *x = y; // error
          }
          

          Вот так в D объявляется изменяемый указатель на неизменяемый int:
          const(int) *x
          

          Если указатель константный, то и данные, доступные через него — тоже. Вот это настоящий const-нацизм.


          1. Chaos_Optima
            15.01.2016 18:37
            +5

            В С++ это тоже есть const int* const x


            1. burjui
              15.01.2016 22:08
              +1

              Я в курсе, но в D const int* x по умолчанию не даёт выстрелить в ногу, а C++ вариант const int* const x выглядит уже не так опрятно. В C++ вообще много чего есть, но есть языки, в которых это сделано лучше.


          1. mustitz
            16.01.2016 00:12
            +1

            const и restrict дают очень много в плане оптимизации, потому что любая модификация памяти через указатель должна сбрасывать все закешированые ранее в регистрах значения. В C++ для этого есть свои достаточно специфичные правила (перечитываются только значения того типа, который изменился по указателю). Кто-то даже шутил, что использование restrict при реализации математических методов позволяет C по скорости догнать FORTRAN.

            Если брать const как защиту от случайной модификации, то теоретически да. Но на практике я больше вспоминаю случаи, когда погорячился с const, и указатель надо было вернуть в неконстантное состояние, часто по длинной цепочке, иногда с пересмотром архитектуры. А вот когда бы это действительно помогло… не помню… Может быть, но уверенности нет.


            1. justaguest
              16.01.2016 11:06
              +1

              Это как парадокс, что пользователи чаще пишут отзыв при плохом происшествии; когда же все идет отлично, они молчат — люди просто не обращают внимание, что все хорошо. Я могу вам назвать, когда const действительно полезен — прежде всего при отладке. Как только у вас что-то идет не так, а особенно в трудностях локализации ошибки — const в аргументах и теле позволяют сразу сказать: «Ага, я не модифицировал это значение, значит ошибка не тут!». В частности может помочь, когда переполнение буфера (да, я в курсе про address sanitizer, но предположим его у вас нет), и все выглядит, словно изменяется именно эта переменная.


      1. vladon
        18.01.2016 16:57
        +1

        Вот и Линус Торвальдс такой же, не понимает он C++ — и все вынуждены писать в ядре на Си.


        1. sborisov
          18.01.2016 16:57

          что такое ABI в курсе?


          1. vladon
            18.01.2016 16:59
            +1

            В курсе. Поэтому предпринимаются попытки его стандартизировать. Просто не было необходимости.


          1. 0xd34df00d
            18.01.2016 17:08
            +2

            Ну и причём ABI к ядру, которое только относительно недавно стало собираться чем-то, отличным от gcc?

            Кстати, я тут ядро собрал gcc 4.8, а модуль потом дособрал с gcc 4.9, чего-то модуль не загружается. Как же хвалёный стабильный C ABI?


  1. maaGames
    15.01.2016 10:02
    +4

    > ООП… почему надо так жёстко объединять код и данные.

    Кхм… Я не понял связи между ООП и объединением кода с данными.

    Посмотрел игры автора, половину из них можно было написать на JavaScript или вообще на HTML5. Только зря любимую сишку насиловал…

    Раз такое пропустили на Хабр (и ведь даже не на Гиктаймс, а на Хабр!), может и мне стоит написать статью, как игру за три дня написал. Пусть мне уже и объяснили, что три дня это довольно много.)


  1. AjnaGame
    15.01.2016 10:19
    +40

    гиф анимация
    image


    1. mapron
      15.01.2016 21:32
      +4

      «Я пишу на голом Си» теперь для меня заиграло новыми красками!


  1. juryev
    15.01.2016 11:19
    +1

    Всяк кулик своё болото хвалит.


  1. groaner
    15.01.2016 11:39
    +1

    Самый обстоятельный, убедительный и отлично написанный разбор того, почему C в сто раз лучше чем C++ — C++ Frequently Questioned Answers. Вот бы ещё кто-нибудь совершил подвиг и на русский язык это перевёл.


    1. 0xd34df00d
      15.01.2016 15:18
      +3

      Прочитал несколько первые ответов из Big Picture Issues — так можно про любой достаточно популярный язык написать. 6.1 для того же C применим простым удалением из текста всех плюсиков.

      Ну и необоснованные утверждения — это супер.
      «Templates are hard to use» — а я говорю, что нет, они простые.

      Using C instead of C++ has several practical benefits: faster development cycle, reduced complexity, better support by tools such as debuggers

      Ну это просто смешно. Тут я не выдержал и закрыл страничку, извините.


    1. izvolov
      15.01.2016 17:33
      +1

      Автор просто плохо знает язык.
      Многие вещи субъективны, многие откровенно ошибочны, многие устарели в связи с выходом 11-го и 14-го стандартов или стремительно устаревают в связи с подходом 17-го.


  1. groaner
    15.01.2016 11:41
    -1

    Пункт насчёт скорости компиляции не совсем понятен — вряд ли C компилируется быстрее чем, например, C# или Java.


  1. pascualle
    15.01.2016 12:14
    +3

    Наконец-то я нашел 100% однодумца!


  1. elanc
    15.01.2016 12:24
    +1

    Кстати, раз упомянули разработчиков в области GameDev, творящих на Си: слежу за этим гражданином — www.twitch.tv/quel_solaar/profile
    И уж поверьте — уровень графики в его текущем проекте просто превосходный!


    1. AllexIn
      15.01.2016 12:33
      +1

      Ну уж графика-то в современном мире от языка вообще не зависит.


      1. elanc
        15.01.2016 12:41
        +2

        Так это я, как бы, в ответ комментаторам выше, которые говорят, что у автора первоисточника статьи «графика 90х» в играх.


    1. creker
      15.01.2016 12:49
      +3

      Уровень графики зависит от самой графики — шейдеров и арта. Написан движок на С или C# уже имеет малое значение, потому что современные проекты упираются в GPU в подавляющем большинстве случаев. Взять тот же Unity на mono. Когда же тебе важна CPU производительность, то выбор практически всегда С++. Банально, настолько сложные архитектурно проекты сложно писать на С и С++ не случайно является де-факто стандартом в геймдеве.


  1. Fedorkov
    15.01.2016 13:36
    +2

    Ода золотому молотку


  1. potan
    15.01.2016 18:49
    +8

    В качестве альтернатив Rust даже не упоменается. Автор про него не слышал?
    Хотя Rust все-таки немного сложнее C, эта сложность оправдана — ни чего лишнего там нет.


    1. vladon
      18.01.2016 15:05
      +1

      Я бы сказал, что он даже сложнее C++


      1. potan
        18.01.2016 15:36
        +3

        В C++ очень много неочевыдных подводных камней, типа невиртуальных деструкторов или изменение класса объекта в процессе работы конструкторов.
        В Rust же таких неожиданностей нет. Да и сложных концепций, типа раследования.
        Владение и заимствование — достаточно сложная и непривычная вещь, но она проще, чем «умные указатели».
        Так что в целом Rust на порядок проще.


        1. vladon
          18.01.2016 15:39
          +3

          Зная C++, конечно, Rust покажется лёгким ;-)


          1. potan
            18.01.2016 16:00

            А знание Rust при изучении C++ сильно поможет?


            1. vladon
              18.01.2016 16:56
              +3

              Я пока не встречал людей, которые изучали в этом порядке :-) Но конечно же поможет.

              Это людям с языками с GC в бэкграунде трудно изучать C++ или Rust.


  1. Ivan_83
    16.01.2016 03:37

    Языков с каждым днём всё больше.
    Некоторым нравится синтаксис, другим что решены какие то проблемы которые их лично очень беспокоили.

    Тем временем только С остаётся языком живым, мало меняющимся и совместимым со всеми остальными языками и платформами.
    Те я могу взять код которому лет 30 (почти как мне) и может быть с минимальными правками его собрать и запустить. (речь про алгоритмы не привязанные к железу/архитектуре)
    И смогу тоже самое сделать ещё лет через 30.
    Можно один раз в жизни написать какой то алгоритм и потом всю жизнь им пользоваться где угодно просто подключая 1-2 файла.

    Уверен, мало кто тут пережил смерть своего любимого языка и осознал что всё что было написано за предыдущие годы теперь просто бесполезные файлы.
    Автор прошёл это с флешем, я с вижалбейсиком и квикбейсиком.

    Ещё один важный аспект в том, что код на чистом Си реально легко таскать между платформами, за исключением нюансов с BE/LE, но это мелочи в сравнении с тем что в других языках оно вообще практически никак.

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

    Не спорю, писать маленький проект с нуля на си не очень то и быстро/удобно, особенно где никакой число/байто грызки не требуется.
    Но на средних проектах, уже может статься что можно заюзать массу кода который кто то написал, и не просесть в производительности на расчётах или в/в — всегда можно хоть до AVX/NEON дойти и выжать все соки из железа.
    Большие проекты это всегда боль, при любом языке.

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


    1. creker
      16.01.2016 17:53
      +4

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

      Ох уж эти контрол фрики. Подобные рассуждения обычно свойственны, простите уж, мало опытным программистам. Они вечно хотят все контролировать, все делать сами, знать обо всем на свете. Я помню по себе, когда в ObjC с ручного управления памяти перешли на автоматический подсчет ссылок. И аргументы для самого себя у меня были теже самые — нафиг мне это надо, лучше я сам буду все делать, сам буду знать, что там творится и как. Если что сломается, то сам и починю. В какой-то момент просто приходит озарение.

      Низкий уровень Си является огромным его минусом и всегда таким будет. Минусом это перестает быть только тогда, когда задача требует этого. Именно требует. Ядро ОС требует. Драйвера требуют. Игры — игры автора никаким местом не требуют. Это просто прихоть автора, ничем объективно не обоснованная. А вот игры ААА уровня, особенно для консолей — требуют. Но там Си никому не нужен, используют С++. Последний, собственно, нормально подойдет и для ОС с драйверами. Например, Apple для драйверов выбрала С++ и ООП интерфейс developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/Features/Features.html#//apple_ref/doc/uid/TP0000012-TPXREF101

      Что до линукса, то смотря на их забавные попытки, по сути, реализовать C++ на Си в той же VFS, то там тоже не видно причин не использовать С++. Просто Линус против, да и время сыграло свою роль. В то время компиляторы вполне возможно могли быть не так хороши.


      1. grossws
        16.01.2016 18:05
        +1

        Что до линукса, то смотря на их забавные попытки, по сути, реализовать C++ на Си в той же VFS, то там тоже не видно причин не использовать С++
        А зачем там плюсы? Всё равно rtti и exceptions придётся отключать для ядра, плюс развлечения по борьбе с mangling, что приведёт код к Си-подобному. Хотя шаблоны были бы крайне приятны.


      1. Ivan_83
        18.01.2016 10:59
        +2

        «Низкий уровень Си» это не минус, это особенность языка, ради которой он в общем то и создавался и за счёт которой до сих пор живее всех остальных.
        Кроме ядра и дров полный контроль необходим в архиваторах, кодеках, криптоалгоритмах и любых других алгоритмах где важна скорость выполнения/эффективность. Это противопоставление не ++ а скорее другим языкам.
        ООП ещё и в новых дровах венды есть, как минимум попытка, там целый фреймворк для этого.

        2 0xd34df00d:
        Формально я тоже иногда пишу на ++: в вижал студии оно как то всегда по дефолту. Но ничего из ++ при этом не использую.


        1. 0xd34df00d
          18.01.2016 15:26
          +4

          Формально я тоже иногда пишу на ++: в вижал студии оно как то всегда по дефолту. Но ничего из ++ при этом не использую.

          Не очень понял, причём тут это, ну да ладно. Я пишу на C++, фичи из C++ использую, и мои волосы всё ещё гладкие и шелковистые.


      1. vladon
        19.01.2016 13:48
        +2

        Дайте я вас расцелую


    1. 0xd34df00d
      16.01.2016 18:58
      +2

      В случае Си мне всегда понятно что оно делает и как, никаких махинаций за ширмой, никакого волшебства, нюансы конечно есть но их довольно мало в сравнении с языками которые на себя берут заметно больше.

      У меня полностью аналогичная ситуация, коллега! Только для C++.

      А патчи к ядру или ещё чему то всем известному смотрятся круче, чем какой то там неведомой штуке на новом крутом языке :)

      Да нормально всё смотрится в резюме. Даже личкрафты.


  1. bigov
    17.01.2016 10:19
    +5

    Спасибо за перевод, прочитал с интересом пост и особенно комментарии. Наверно автор мог бы сократить свой пост до строк: я пишу на ванильном С, потому что не смог до конца освоить ничего более сложного. Но в этом случае его пост бы не перевели для хабра.