Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Этим летом на онлайн-конференции C++ Russia побывал самый почетный гость, какой только может быть на мероприятии по C++: создатель этого языка Бьярне Страуструп. Мы поговорили с ним о контроле над языком, нововведениях, удалении старых функций, о том, почему у языка нет четкой экосистемы, и как так получилось, что у С++ нет стандартной сетевой библиотеки.
А поскольку сообщество C++ вечно обсуждает Rust, не обошлось и без вопроса о заимствованиях между этими языками.
Бьярне не нуждается в особых представлениях, но у него столько активностей и заслуг, что попробуем перечислить:
- написал множество публикаций, в том числе книги «Язык программирования С++» и «Программирование: Принципы и практика использования C++»
- работает управляющим директором в отделе технологий компании «Морган Стенли» в Нью-Йорке
- преподает в Колумбийском университете
- принимает активное участие в работе комитета по стандартизации C++
- состоит в Национальной академии инженерии США, IEEE, Ассоциации по вычислительной технике. Исследует программирование в области распределенных вычислений, инструменты развития ПО и языки программирования.
- Магистр и заслуженный профессор Орхусского университета и доктор по направлению «Информатика» Кембриджского университета и почетный член научного сообщества Колледжа Черчилля, заслуженный профессор Санкт-Петербургского ИТМО
Вопросы ему задавали С++ программист, организатор С++ Siberia Сергей Платонов и руководитель разработки бэкенда Яндекс.Лавки Сергей Федоров. Под катом — перевод, а также видеозапись интервью для тех, кто хочет послушать на английском.
Об истории
Сергей Платонов: Спасибо, что присоединились к нам. Говорить с вами — большая честь. У нас есть несколько вопросов от сообщества, но хотелось бы начать с тех, что проще и короче. Начнем с истории, поскольку об этом часто спрашивают. В первую очередь хотелось бы сказать, что вы самый упоминаемый спикер. Каждый раз, когда мы спрашиваем у зрителей, кого следует пригласить на конференцию, первым называют ваше имя. Зрителям хотелось бы поучаствовать в обсуждениях, в живом общении. Не могли бы вы в паре предложений рассказать, как вы стали создателем C++? С чего все началось? Мне кажется, все читали «Дизайн и эволюцию», но если возможно, хотелось бы услышать ее укороченную версию.
Бьярне: Я пришел к C++, когда захотел создать систему для Bell Labs, которая бы стала первым UNIX-кластером. Это была бы система для распределенных вычислений, объединенная в общую сеть из нескольких компьютеров. Мне предстояло написать код, который бы работал на нижнем уровне, на уровне железа: диспетчеры памяти, планировщики процессов, сетевые интерфейсы и все в таком духе. И при этом нужно было уйти от железа. Мне нужно было перейти на высший уровень, чтобы заставить один код взаимодействовать с другим, используя определенный протокол передачи данных определенным образом.
Итак, мне нужен был язык программирования, который бы работал и на низшем, и на высшем уровне. В то время было как минимум с десяток языков, которые справлялись с задачами низшего уровня, C был одним из них. Лаборатория Денниса Ритчи и Брайана Кернигана находилась в одном коридоре с моей, поэтому дальнейшие действия казались очевидными, но на тот момент я подумал, что этот язык работал со слишком низким уровнем. Мне были нужны механизмы абстракции. У меня был опыт работы с Симулой, о которой я узнал от Кристена Нюгора. И я взял классы из Симулы, перенес их в C, сделав его достаточно эффективным для программирования сложных систем. На второй неделе работы над проектом я добавил конструкторы и деструкторы. Тогда они были нужны, в том числе для управления ресурсами. Затем я добавил то, что сейчас называется прототипами функций и проверку аргументов функции.
Основой C++ стала его возможность эффективной абстракции, ядром которой являются статическая проверка типов, конструкторы и деструкторы, что в совокупности позже начало именоваться как RAII (Resource Acquisition Is Initialization, «получение ресурса есть инициализация»). В 80-е у меня было совсем мало времени на изобретение хороших названий для хороших технологий, лучше, чем RAII, я ничего не придумал, так что уж имеем то, что имеем.
Контроль над языком
Сергей П.: Вы не помните тот момент, когда C++ ушел из-под вашего контроля в руки сообщества?
Бьярне: У меня, на самом деле, не было никогда контроля над языком в полном смысле слова. Как только языком начинают пользоваться, у его создателя появляются свои обязанности. Нужно отвечать на запросы пользователей. В моем случае это случилось спустя шесть месяцев после запуска проекта. Появился пользователь, и я потерял возможность выносить единоличные решения. Я не мог решиться пойти на то, чтобы все сломать.
Потом, где-то спустя 10 лет, люди из IBM и Sun, а также представители HP пришли ко мне в офис и сказали: «Знаешь, Бьярне, надо сделать так, чтобы C++ соответствовал нормам ISO». Я тогда объяснил, что это невозможно. Было слишком рано, я не был готов. После часового разговора я согласился, так как выбора у нас не было. Они объявили, что не могут позволить своим компаниям зависеть от чего-то, что зависит от их потенциального конкурента, например, AT&T. Помню, они сказали: «Мы, конечно, тебе доверяем, но скорее всего мы назначим тебе начальника». И тогда мы начали стандартизацию.
В целом, процесс стандартизации очень непрост и сильно раздражает. Многие стороны со своими потребностями должны прийти к единому мнению относительно вещей, на которые у всех разные взгляды. Спустя годы мне кажется, мы все сделали совсем недурно. Сегодня у нас есть проблемы посерьезнее. Тогда собиралось 60 человек, все друг друга знали, было доверие. Сейчас у нас 230–240 человек, мы не можем хорошо узнать друг друга. Работа сейчас строится иначе, и она стала труднее. И, конечно же, в этом году нам приходится связываться через Интернет, потому что собрания запрещены. Пройди встреча комитета по C++ в течение недели в одном небольшом помещении, мы бы точно потеряли часть людей — языку это бы не пошло на руку.
Работа в комитете
Сергей Федоров: Не могли бы вы рассказать, какую позицию в комитете занимаете на данный момент?
Бьярне: Исторически сложилось так, что я был главой эволюционной группы. Пять лет назад я ушел на пенсию. Вилле Воутилайнен занял мою должность. Моя неофициальная должность всегда заключалась в контроле целостности языка и видении дальнейшего движения в целом, а не на уровне отдельных функций. Мало кто занимается этим. Многие просто обращают внимание на отдельные фишки языка, оценивают их, не обращая внимания на взаимодействие разных параметров внутри языка. Некоторые же люди, в том числе и я, смотрят на язык в целом. Общие аргументы ложатся в основу. Как следствие, я вхожу в небольшую группу людей, долго связанных с C++, которая заботится о сохранении взятого однажды курса.
Вы, возможно, видели мои выступления, где я рассказывал о «Вазе» — шведском боевом корабле, построенном в 20-е годы XVII века.
Его строили по указу короля, согласно которому новый корабль должен был стать самым красивым и самым мощным морским орудием в португальской зоне. Затея была хороша. Ему дали название в честь королевской династии Ваза. Строители было приступили к работе, однако вскоре заметили, что потенциальный враг начал строительство боевых кораблей большего размера с двумя орудийными палубами вместо одной, что на тот момент было инновацией. Тогда все поняли, что дело идет к большому позору, поскольку если в морском бою сойдутся два корабля — однопалубный и двухпалубный, первый быстро пойдет ко дну. Тогда король сказал, что нужен двухпалубный корабль. Королю был нужен самый большой, самый мощный корабль, который также мог бы использоваться как средство дипломатии. Оценив план строительства, все поняли, что нужен был корабль большего размера, а для пущего размаха на него должны были установить статуи. Тогда у главного инженера начались проблемы. По слухам, он покончил жизнь самоубийством после постройки корабля или немного времени спустя. Королю сказали, что нужно больше времени на переработку основы конструкции. Король не согласился. В принципе, это похоже на ситуацию, когда управляющий высокого ранга не видит всех нюансов, проявляющихся где-то на нижнем уровне, где трудятся простые рабочие.
Итак, корабль следовало построить к сроку. Они успели. После создания чего-либо необходимо это что-либо испытать. Боевые корабли проходили испытания по следующему принципу: команда корабля в полном составе встает у одного борта. Затем по команде бежит к другому борту, добежав, разворачивается и бежит обратно. И так 14 раз. Если корабль не переворачивается, значит, он прошел испытания. Команде удалось сделать 7 пробегов, а затем испытание остановили из страха, что он опрокинется. Собственно, испытания провели не полностью, сэкономив на этом. Очень зря. Как бы там ни было, в день спуска на воду ничего не предвещало беды: развевающиеся флаги, духовой оркестр, прекрасные статуи, гром холостых выстрелов. Корабль проходит через бухту в Стокгольме, которая является серединой маршрута. Но вдруг порыв ветра переворачивает корабль, который в итоге идет ко дну. Спустя 350 лет его достали со дна и разместили в красивом музее в Стокгольме. Если когда-нибудь будете в этом городе, обязательно посмотрите на корабль «Ваза». Он очень красив и выглядит впечатляюще.
Несколько лет назад мы собирали комитет по стандартизации в Стокгольме. Тогда мы все дружно пошли в музей, чтобы посмотреть на корабль, и тогда же на долгие годы вперед закрепился наш девиз: «Не забывайте, что случилось с "Вазой"». Правильно проработайте базу, не экономьте на испытаниях и не заказывайте себе слишком много красивых статуй. Этот девиз начал постепенно забываться, и я пытаюсь напоминать о нем людям. Может быть, нам стоит еще раз собраться в Стокгольме.
Если бы тогда они построили корабль на полтора метра шире, катастрофы бы не произошло, корабль вышел бы на славу. Но тогда люди решили не учитывать базовые вещи. С другой стороны, они и не ошиблись: построй они старый корабль по хорошо проработанным планам, он бы не смог выполнить возложенную на него задачу. Обычный корабль вряд ли мог стать средством для успешной дипломатии. Он и в сражении бы не выстоял. В общем, им пришлось что-то придумывать. Я всегда рассказываю эту историю, чтобы напомнить людям о том, что при улучшении чего-либо нам нужно быть очень осторожными и не добавить что-то, чего не выдержит старая база.
Нововведения
Сергей Ф.: К слову о красивых новых пушках, в новых стандартах C++ присутствуют функции, которые вас особенно раздражают?
Бьярне: Да нет. Мне кажется, C++20 будет отличным стандартом, мы наконец-то воплотили в жизнь концепции. Я бы хотел внедрить их еще в 1986—1988 годах, когда я создал шаблоны, но не знал, как это сделать. Мы попытались в стандарте C++11, но у нас не получилось все сделать как надо. Я надеялся, что к стандарту С++17 все будет готово, поскольку у нас появилось необходимое понимание, но в итоге, они появятся лишь в С++20. У нас наконец-то появится нормальное обобщенное программирование. Благодаря этому выражения станут четче, проще, и все будет работать намного быстрее. Добавьте к этому constexpr, и вы получите сильно упрощенное обобщенное программирование и сильно ускоренное метапрограммирование во время компиляции.
Другое нововведение, которым я очень доволен, это сопрограммы. Сопрограммы были в основе C++ в первые 10 лет. Я тогда писал симуляции и то, что сегодня называют многопоточными программами, с помощью сопрограмм. Мои симуляции были меньше и быстрее любых аналогов. А также они были меньше и быстрее потоков. Здорово, что мы вернули сопрограммы. Мы когда-то ушли от них потому, что компания Sun не хотела внедрять их в архитектуру Spark, поскольку очевидная реализация управляет стековыми фреймами. Сегодня же мы имеем более быстрые сопрограммы.
И теперь перейдем к последней функции, которая, скорее всего, будет играть важнейшую роль в долгосрочной перспективе. Это модули. По сути, это относится к организации программы, а не к написанию кода. Если вернуться во времена Windows DNA, я помню, как я мечтал о нормальном методе разнесения программ по частям. Нам приходилось пользоваться заголовочными файлами. Тогда в 80-е и 90-е мы знали, как лучше. Введение новых возможностей в язык с несколькими сотнями миллиардов строчек кода не так просто, но мы сделаем это. Итак, модули. Они значительно повысят скорость компиляции. Я видел, как скорость возрастает в 50 раз, если сравнивать с методом использования заголовочных файлов. Надеюсь, что большинство программ ускорится, скажем, в семь раз. И, наконец, мы нашли способ предотвратить распространение макросов по всей системе. Вы помещаете макрос в заголовочный файл, кто-то затем включает ваш заголовочный файл в свой файл, затем этот файл включается в следующий файл, и так ваш макрос присутствует в конечном файле, создатель которого даже не знает о существовании вашего заголовочного файла, из которого появился макрос. С появлением модулей эта проблема уйдет. Теперь код чище, и именно благодаря этому повышается скорость компиляции. Думаю, эти три функции — самые важные, они будут в значительной мере влиять на написание кода в следующие десять лет.
Есть небольшая проблема отсутствия поддержки стандартной библиотеки. Сегодня не существует одного стандартного набора модулей, кроме того, сопрограммы не поддерживаются библиотеками в полной мере. В стандартной библиотеке есть некоторые концепции, поэтому, я считаю, у нас все будет хорошо. Надеюсь, в стандарт С++23 будут включены все новые возможности. Трудно обеспечить библиотеками то, что пока не внедрено. Мы решили, что сначала введем новые функции в язык, чтобы опробовать их в деле в разных масштабах. Нам нужны программы с миллионами строчек кода — в них новые возможности будут использоваться в полной мере. Затем, набравшись опыта, мы доработаем их в стандарте С++23, и их использование станет проще и, наверное, быстрее.
Удаление старых функций
Сергей П.: Что насчет функций, которые не используются в языке программирования? Вам не кажется, что некоторые из них можно было бы удалить? И поскольку у нас есть трехсекундная задержка, я позволю себе перефразировать вопрос. У комитета есть какие-то возможности по удалению старых функций из языка? Я спрашиваю потому, что язык становится все объемнее, а следовательно, труднее для изучения. Людям все труднее поспевать за появляющимися нововведениями.
Бьярне: Этот вопрос касается большого и сложного дела. Не думаю, что в C++ есть какая-либо основополагающая функция, которую мы могли бы удалить, не разозлив несколько сотен тысяч или даже миллион пользователей. Такого не должно произойти. Если посмотреть на этот вопрос философски, я могу сказать, что основные функции языка хороши, другое дело — мелкие детали. Но с этим мы ничего поделать не можем. Мы разрабатываем язык, смотрим на то, как он функционирует, опираясь на отзывы. Однако, как бы то ни было, когда мы вводим что-то масштабное, убрать это нововведение не так просто. Несколько раз мы пытались удалить старые возможности, и каждый раз у нас не получалось. В рамках стандарта ISO мы можем сократить функционал языка с помощью так называемой депрекации, объявляя функции устаревшими. Мы объявляем пользователям, что одна из функций языка больше не будет использоваться и мы удалим ее через 3–5–10 лет. Этот подход не работает с основополагающими функциями.
В течение десятилетия нам никак не удавалось убрать триграфы. Сейчас мы от них избавились, при этом большинство даже никогда не слышало о триграфах. Оказалось, что каждая машина в IBM не может запуститься без триграфов. Убрать триграфы языка — убить IBM. Такого не должно произойти, да и в IBM любят цепляться за старые фишки. И снова нам приходится сообщать о том, что мы удаляем возможности, что ими не стоит пользоваться. Нам было очень сложно избавиться от правила implicit int, хотя в C++ его никогда и не было, оно пошло от C.
Все мечтают избавиться от тех вещей, которые им не нравятся, от всего устаревшего и прочего. Но договориться о том, что устарело, что не нужно, никто не может. Получается, что не существует согласия между 4,5 млн программистов, пишущих на C++. Более того, его никогда и не будет. Добавьте к вышесказанному и то, что после удаления функции из языка, поставщики компиляторов будут вынуждены поддерживать ее еще лет 20–30. В общем, что-то убрать почти невозможно. Даже если мы придем к согласию, все равно удаление не пройдет легко.
Сегодня мы не можем поменять или убрать основополагающие функции, при этом тратить время на удаление каких-то мелких функций кажется совсем смешным. Так как же заставить людей двигаться дальше? Во-первых, обучить их писать на современном C++. Сегодня все еще много тех, кто начинает изучать C и загоняет себя в ловушку бессмысленного распределения памяти, вместо того, чтобы обратить внимание на векторы, RAII и прочее. Во-вторых, нам нужно поддерживать современный подход к программированию, который проще и благодаря которому создаются более быстрые и менее объемные коды. Когда кто-то начинает писать операции над строками в стиле из C, он обычно получает баги и медленный код. Эксперты справляются лучше, но у экспертов, как правило, есть дела поважнее.
Я работаю с друзьями над C++ Core Guidelines. Если им следовать, можно сказать, набору правил, а не беспорядочно использовать все функции языка, ваш код будет лучше и вы пойдете спать раньше. Да, это правила. Нам всем не нравятся правила, их трудно запомнить, поэтому для них нужна поддержка. Правила отчасти зависят от стандартной библиотеки и от 10 небольших компонентов из GSL (guidelines support library), которые мы хотим перенести в стандарты, чтобы избавиться от необходимости в GSL.
Например, мы добавили span в стандарт C++20. Span – это простая абстракция, по сути, указатель плюс размер. Если нужна ссылка на непрерывный набор элементов, используете span, который знает расположение элементов и их количество, поэтому вы можете задать диапазон и, при желании, произвести проверку диапазона. При этом у вас нулевой шанс ошибиться.
Предположим, у нас есть массив, мы берем span, присваиваем ему значение массива. Span обратится к массиву, поймет, какие в него входят элементы, они получат тип span-а. Далее он узнает количество элементов в массиве, возьмет этот размер. Все, вы получаете правильную абстракцию непрерывной последовательности битов, как с объектами, и это вам необходимо для коммуникационных программ и прочих низкоуровневых дел. Деннис Ритчи хотел сделать что-то похожее в C, но ему сказали, что ничего не выйдет. Это все не ново, но полезно. Это одна из мелочей, которая реально помогает в работе.
Не все мелкие фишки можно сравнить с бесполезными, но очень помпезными статуями на «Вазе». Некоторые фишки действительно отвечают запросам сообщества. В общем, ответом на ваш вопрос будет то, что мы не можем избавиться от старых функций, но мы можем издать рекомендации, согласно которым, их лучше не использовать. Мы можем создать инструменты статического анализа, которые бы принуждали подчиняться этим рекомендациям. В частности, я работаю с сотрудниками Microsoft и Facebook над проверками безопасности памяти. Эти проверки проводятся с целью предотвратить повреждение памяти, доступ к удаленному объекту, потерю ресурсов, а также способствуют использованию RAII.
А при включении другой статической проверки, первая будет предотвращать переполнение буфера. Например, при использовании указателей вы рано или поздно придете к переполненному буферу. При использовании общих указателей рано или поздно дело придет к висячему указателю. Например, согласно нашим правилам, вы должны использовать span вместо указателя. Используете RAII, затем включаете проверку (сейчас она развертывается в Visual Studio, поэтому то, чем я говорю, — реальность) и избавляете себя от всех проблем с памятью. Проверка обнаружит все проблемы.
Я бы хотел, чтобы проверка была доступна для использования вне Visual Studio, чтобы этот инструмент можно было использовать на любой платформе. К сожалению, такого пока нет. Мы пришли к соглашению, что однажды эта проверка будет доступна для любой платформы, правда, пока не ясно, когда это случится. Сейчас же приходится запускать Visual Studio и прогонять программы через нее. Всегда лучше работать с несколькими компиляторами, чтобы защититься от багов самого компилятора.
Об экосистеме
Сергей Ф.: Почему, по вашему мнению, у С++ нет четкой экосистемы?
Бьярне: Потому что у языка нет законного владельца. Нет одной компании, которая бы все контролировала. Каждый создает что-то свое. Мы начинали вообще без финансирования, если говорить об исследовательских проектах в Bell Labs. Я самостоятельно делал 98% работы по первому коммерческому запуску языка: составлял документацию, учебные библиотеки и прочее. Наш рекламный бюджет тогда был 5000 долларов на три года, и тогда я вернул 1000, потому что не знал, как правильно распорядиться средствами.
Многие не понимают, что у C++ никогда не было бюджета. Вместо денег было сообщество, причем не одно сообщество, а множество. Проблема состоит не в отсутствии графического интерфейса, а в том, что их 25. Проблема не в том, что у нас нет системы сборки, а в том, что их 7. Это я еще преуменьшаю. Люди не могут прийти к единому мнению. Все принадлежат к разным сообществам. Все хотят делать по-своему, никто не хочет слияний. Некоторые проблемы лежат в коммерческой плоскости, некоторые части имеют открытый код, аспекты вызывают проблемы из-за большого самомнения некоторых лиц. В итоге у нас демократический хаос, и я не знаю, как его прекратить.
Возможно, если бы я обладал лучшими навыками организации, мы могли бы еще что-то сделать, когда это было возможно, а возможно это было в 80-е. Правда, в 80-е и особенно в 90-е все хотели создать свое сообщество, организованное вокруг своего решения и своего подхода. Тогда в игре были Microsoft, IBM и еще пара-тройка серьезных компаний. Все пытались создать что-то вне конкуренции, чтобы заполучить побольше пользователей. Компании тогда приходили к решениям, которые были несовместимы с решениями конкурентов, чтобы потребители вдруг не ушли к последним. У нас же было наибольшее количество инструментов, и в большинстве случаев, это не является преимуществом. Как определиться с системой сборки? Как определиться с графическим интерфейсом? Сложно. Подумайте, каково было новичку.
Сергей П.: У нас нет простой системы сборки, которая будет без проблем работать в любой системе.
Бьярне: Нет-нет, мы можем предложить вам как минимум три, которые плюс-минус подходят под ваши критерии.
О рейтингах и популярности языка
Сергей П.: Вам важно то, какое место C++ занимает в рейтингах? Следите ли вы за популярностью языка, за какой-либо статистикой? У нас на конференции будет отдельный разговор о C++ и его месте в мире.
Бьярне: Не думаю, что до конца понял вопрос. Попытаюсь ответить на него и, если я уйду не в ту сторону, поправьте меня. Я стараюсь сосредоточить внимание на самом языке и стандартной библиотеке. Я не лучший собеседник по темам вселенной C++, плеяды доступных инструментов, рекламных аспектов или открытого кода. Слишком много информации для одного человека. И я не обращал внимания на статистику. Ее очень сложно получить. Сложно считать пользователей.
Хорошо, что кто-то этим занимается. Проводятся опросы, часть информации доходит и до меня. Поэтому-то я и оперирую цифрой в 4,5–5 миллионов разработчиков C++. Но кто такой разработчик? Кто такой программист? Учитывать ли студентов? А всех студентов или только очников? Все эти цифры очень условны, но я, как по мне, опираюсь на самые скромные подсчеты. Я бы мог назвать и число побольше, но не собираюсь, поскольку тогда мы будем учитывать тех, кто пользуется C++ не постоянно, а это не лучший способ подсчета.
Можно спросить у тех, кто может сказать, сколько у них пользователей потому, что они как минимум могут подсчитать количество заплативших за продукт или число скачиваний, что, в целом, тоже не лучший метод подсчета. Я раньше руководствовался такой логикой: если люди не жалуются, значит, они не пользуются C++. Конечно, у нее есть свои минусы. Это я тоже знал. Компания AT&T решила провести опрос пользователей об их опыте, поскольку была необходимость следить за распространением языка, хотя он и был бесплатным. Они обнаружили, что 4 из 5 разработчиков используют C++. Это расходилось с моими подсчетами, в которых я не учитывал тех, кто не жаловался. В общем, считать — проблематично.
Сетевая библиотека
Сергей Ф.: Вы говорили, что начали разрабатывать C++, когда вам понадобилось средство, чтобы преодолеть сложность организации сетевой системы. Как же так получилось, что у C++ нет стандартной сетевой библиотеки?
Бьярне: Опять же, проблема не в том, что нет сетевой библиотеки. У нас нет стандарта. С середины 80-х появлялось много библиотек. Сегодня многие пользуются библиотекой Asio, которую технически можно назвать стандартной. Думаю, что в C++23 мы добавим её. Но начинаются разговоры, что нужно больше поддержки. Помимо Asio, нужно добавить то, чего не дает Asio. И это обыденный хаос в мире C++. У нас даже нет стандарта для места хранения библиотек. Никто как следует не позаботился о создании хорошего сообщества C++. Даже удивительно, как этот язык пережил десятилетия конкуренции. Я написал статью о последних 15 годах развития C++ для конференции по истории языков программирования. Эта статья стала доступна буквально две недели назад на сайте Ассоциации по вычислительной технике. Поищите его там. Или можете пройти на мою страничку и найти ее в разделе со статьями. В статье я объясняю все события, произошедшие за последние 15 лет. Она называется Thriving in a Crowded and Changing World. В ней описываются последние 15 лет развития C++, работа над стандартами 11, 14, 17 и 20, а также некоторые проблемы сообщества. На большую часть заданных сегодня вопросов можно найти более глубокие ответы именно в статье. Сейчас я не могу отвечать в той же степени пространно. В интервью все рассуждения так или иначе абстрактны, нет возможности подтвердить слова документацией, но большая часть сказанного мною встретится вам в названной статье, оцененной другими учеными. Она не короткая. В ней 168 страниц, 30 из которых занимает список источников. На ее прочтение стоит выделить выходные.
О заимствовании фишек
Сергей П.: Как вы думаете, Rust оказывает влияние на C++ или, может быть, начнет в обозримом будущем? Может ли случиться так, что C++ позаимствует некоторые функции Rust?
Бьярне: По-моему, это скорее Rust заимствует фишки C++, а его разработчики забывают об этом рассказать. RAII был в C++ на протяжении 40 лет. Меня иногда обвиняют в том, что я своровал эту концепцию. Сообщество, конечно, не сильно опирается на академические труды или историю. То же самое и с линейной логикой и семантикой владения, над которыми я работал на протяжении 20 лет. Это фундаментальные вещи, описанные в ключевых рекомендациях. Там же описано и то, что я задумывался об этих вещах еще с середины нулевых. Думаю, мы лучше, чем Rust, просто люди этого не понимают. Я не видел в этом языке ни одной функции, которую я бы очень хотел добавить в C++. Некоторые вещи нельзя просто включить в язык. Ключевые рекомендации могут как-то показать схожесть языка с Rust, но они были написаны задолго до него. Я знаю историю Rust и проблемы заимствования (borrowing), но это слишком сложная тема.
Я экспериментировал с этим в середине нулевых, и в результате экспериментов, код превращался во что-то страшное, слишком много всего приходилось обходить. Кроме того, С++ соотносится с C, что накладывает некоторые ограничения на совместимость, от этого заимствовать только сложнее.
Я обращаю внимание на любой появляющийся язык программирования, ладно, не на любой — их слишком много. Я обращаю внимание на языки программирования с интересными фишками. Если какая-то функция мне нравится и ее можно добавить в C++, я сделаю это и дам ссылку на источник. Люди могут сказать, что это кража идеи; на самом деле, нет, ведь ты сообщаешь, у кого ты ее позаимствовал. Rust не особо привлекателен для заимствований. При этом уже поступают предложения ввести в Rust что-то вроде механизмов для объявления функций устаревшими. Как по мне, это говорит о том, что они еще не пробовали удалять ненужные функции. Да и зачем? Язык еще слишком молод. Они и не могли попробовать удалить что-то устаревшее. А со временем язык будет шириться, и это сильно осложнит задачу. Со временем появляются пользователи и достаточное количество строчек кода. Кстати, был опрос, в котором у людей спросили, на чем им больше всего нравится писать программы. Rust выиграл с отрывом. При этом, из тех, кто отдает предпочтение Rust, лишь три процента написали программу на этом языке. Я тогда удивился. Это же абсурд, какого не ожидаешь.
Сергей П.: Какой язык, кроме C++, вам нравится? Может быть, приходит в голову какой-нибудь редкий язык? Или может быть, вы расскажете об идеях, воплощение которых в другом языке вам пришлось по душе?
Бьярне: Я стараюсь избегать сравнений языков программирования. Не хочу много говорить об этом. У нас есть планы на C++23: мы хотим завершить работу над поддержкой модулей, сопрограмм и еще поработать над концепциями. Если мы все сделаем, то сможем заняться вещами на будущее. Мы, очевидно, позаимствуем из другого языка сопоставление образцов из функционального программирования. Мне нравится эта возможность, я предлагал ее добавить еще в 2015 в C++17. Мы пока собрали рабочую группу, работаем над этим. Возможно, эта возможность появится в C++23. Благодаря этой функции ускорится проверка типов и появится код курсора. Такая версия C++ будет работать и с алгебраическими типами и открытыми иерархиями, и это станет альтернативой dynamic_cast’у. Очевидно, что все эти идеи пришли к нам так или иначе из ML.
Еще одна важная вещь, на которую мы обратили внимание, но вряд ли сможем сделать к C++23 — статическая рефлексия. Рефлексия — отличная штука, которая, к сожалению, очень медленно работает, является очевидной слабостью системы типов и порождает ошибки. Мы уже работали над статической рефлексией. Суть её работы заключается в том, что код узнает от компилятора информацию о программе и на ее основе создает новый код. Тогда бы можно было сказать: дайте несколько программ для чтения и записи файлов формата JSON определенных типов. Когда этот процесс завершится во время компиляции, будет сгенерирована точная поддержка среды для определенного приложения. Сравните это с представлением вашей программы в виде графа, в случае если у кого-то появится необходимость в нем. Все предложения по нововведениям можно найти на сайте WG21. WG21 — это официальное название от ISO для рабочей группы. Все предложения и статьи от 1990 года выгружаются на сайт группы.
Виртуальные функции
Сергей Ф.: Благодарю. Я большой поклонник статической типизации. Что вы думаете о виртуальных концептах или добавлении любого другого type erasure механизма?
Бьярне: Я не могу сказать, что готов ответить на этот вопрос. Я был соавтором статьи о виртуальных концептах, написанной в середине нулевых, но не думаю, что они могут сыграть ключевую роль в развитии C++. И я не большой поклонник type erasure. У нас есть виртуальные функции, некоторые считают их type erasure механизмом. И я думаю, этого достаточно. Наверное, отчасти я говорю так потому, что мы не можем воспринимать сообщество программистов как единое целое. Существует множество сообществ со своими потребностями. Конечно, гибкий и простой код хотели бы многие, но если есть нужда, например, запрограммировать тормозную систему автомобиля или органы управления самолетом или электростанцией, я бы доверил эту работу программистам, работающим рука об руку с инженерами с серьезной подготовкой и инструментами, которые настроены специально под решение их задач и предлагают производительность и надежность высшего уровня. Если речь идет о программировании обработки сигнала для описанных выше технических решений, на первое место встают производительность и надежность. Мне кажется, что 15–20% участников Core Working Group (NB: подгруппа Комитета Стандартизации, занимающаяся ключевыми вопросами развития языка) принадлежат к миру высокой производительности и безотказной надежности, то есть такому, которому отлично подходит C++.
Нам не нужно пытаться сделать из C++ конкурента Python, чтобы завлечь людей, не являющихся профессиональными программистами, но являющиеся экспертами в других областях. Если же нужно добиться скорости и надежности, лучше заменить Python на C++. То же самое действует и в обратном порядке: хотите экспериментировать с C++ — не ослабляйте систему типов и не ослабляйте внимание при написании выражений. Я не буду делать со своим кодом все, что мог бы с ним сделать, не зная наверняка, что мне нужно. Мне кажется, C++ не создан для 80–85% программистов. Всегда стоит помнить об изначальной задумке создания языка: этот язык — распределенная система с прямым доступом к железу и немного повышенным уровнем сложности. Если смотреть на вещи в таком ключе, то любая вещь, нацеленная на то, на что нацелен C++, должна обладать высокой надежностью.
Этот мир сильно отличается от того, в котором существует разработчик приложений. JavaScript хорош в решении тех задач, для которых был создан, а у меня есть правило: не говорить ничего плохого о приложениях, взявших свое начало от C++ как, например, движки JavaScript. Это два разных мира, но иногда они пересекаются. Зачастую С++ ложится в основу и дальше дополняется чем-нибудь еще.
О планах по изменению языка
Сергей П.: Есть ли планы по улучшению целостности языка ценой удаления совместимости с си? Например, можно ли избавиться от препроцессора, чтобы сделать C++ прекрасным?
Бьярне: Основная стратегия и, по-моему, единственная рабочая — предоставить превосходящую альтернативу и надеяться, что устаревшие функции потеряют актуальность. Старые функции нельзя удалить из языка, но их можно удалить из собственного кода. Они могут быть, так скажем, перемещены в запас. Вы можете однажды предложить друзьям или поставщикам перестать пользоваться этими функциями, или пусть они инкапсулируют их. Модули инкапсулируют все старье. В модуле у вас может быть программа, замусоренная макросами и файлами включения. Мне, в общем-то, нет никакого дела до этих файлов включения или макросов, если я не вижу их у себя в коде. Так что эта идея очень важна. По-моему, это единственный способ двигаться вперед. То же можно проделать и с отдельными функциями. Мне, например, не нравятся приведения (casts), я редко ими пользуюсь и, если мне нужно использовать их где-то ближе к уровню железа, на программном уровне я инкапсулирую их во что-то, что использует правильные типы и следует правилам.
Сергей Ф.: Не могли бы вы рассказать, почему бы в C++ не сделать семантику перемещения деструктивной?
Бьярне: На этот вопрос будет трудно ответить в рамках обычного разговора. В целом, это не работало и более того, ломало многие работающие вещи, поэтому не может идти речи о развертывании этого в крупных масштабах. Если даже это сработает, придется приложить много дополнительных усилий. Я не могу здесь вдаваться в подробности. Для начала, мне потребуется как минимум доска. К тому же, придется обсудить несколько версий этой идеи… Нет, придется слишком глубоко копать.
Сергей П.: Люди пишут, что компилятор C++ стал очень сложным. Могли бы вы дать совет, как изучать современные компиляторы, как понимать теорию и где набраться практического опыта? Компиляторы становятся все больше.
Бьярне: Компиляторы объемны и сложны. Мне кажется, сегодня все пытаются улучшить свои компиляторы, ничего при этом не сломав, как это обычно бывает. В данный момент и в Microsoft, и в GCC идет работа по модернизации промежуточного представления. Толчком к этому стали модули, которые должны быть представлены и представлены хорошо. Если проделать эту работу на совесть и представлять модули в виде минимального типизированного промежуточного представления, их работа станет намного быстрее. Если же представить это в виде множества битов, придется перекомпилировать это множество при каждом использовании модулей, что сводит на нет все их плюсы. Да, биты инкапсулированы, но они все еще не дают работать быстро.
Мне кажется всем известно, что GCC и Microsoft улучшают их промежуточные представления. Я знаю, что в Microsoft над этим работает мой старый друг, Гэбриэль Дос Рейс. Когда мы были еще профессорами в Техасе, около 10 лет назад, мы создали представление для C++, которое имело минимальный размер и требовало минимума взаимодействий. Мы дали ему название IPR. Это представление и легло в основу внедрения модулей в Microsoft. По-моему, оно становится все популярнее. Оно в разы меньше и быстрее любой альтернативы. Однако чтобы оно работало с существующими компиляторами, придется добавить кое-какие функции, отсутствующие в минималистичном дизайне этого представления, например отладочную информацию.
Я снова отправлю вас на свой сайт, чтобы вы поискали на нем статью, которая называется A Principled, Complete, and Efficient Representation of C++. Название IPR, как вы могли догадаться, придумал я в свойственной мне «креативной манере», полностью оно звучит так: Internal Program Representation. Мне не нравится, когда его называют AST (Abstract Syntax Tree) потому, что это не синтаксис, не абстрактный и не древо. Но люди все называют это таким образом.
О неопределенном поведении
Сергей Ф.: C++ знаменит своим неопределенным поведением. Есть ли у комитета по стандартизации C++ стратегия, которая позволила бы снизить количество случаев неопределенного поведения?
Бьярне: Многие забывают, что не все случаи неопределенного поведения нежелательны. Вы можете потребовать определенного поведения, которое ошибочно. Например, неопределенное поведение возникает при переполнении целочисленных типов. Вы можете исправить это, используя беззнаковые числа, они используют модульную арифметику, значит, то что было переполнением просто вернёт вас к нулю. Вы получите runtime ошибку вместо неопределенного поведения, которое может быть обнаружено компилятором и другими инструментами. Существует группа, которая занимается неопределенным поведением. Фактически, они работают над тем, чтобы хорошо определить неопределенное поведение: чтобы мы знали, что такое неопределенное поведение и почему оно таковым становится. Мы пытаемся избавиться от всего, что не должно быть неопределенным поведением, поскольку, по-моему, такая проблема есть. Например, лучше иметь определенный порядок вычисления для любого выражения. Некоторые разработчики компиляторов утверждали, что неопределенный порядок давал более быстрый код. Это было неправдой, так что налицо прогресс.
Кстати, Гэбриэль, о котором я упоминал ранее, также работает и над неопределенным поведением. Он стоит во главе рабочей группы, так что да, мы работаем над этим. Просто не стоит верить людям, заявляющим, что любое неопределенное поведение — плохо. Альтернативы могут быть много хуже. Наверное, стоит воспринимать неопределенное поведение как нежелательное, но помнить о том, что альтернативы будут хуже.
Списки инициализаторов
Сергей П.: Спрошу о том, что многие хотели бы не видеть в стандарте. Сейчас речь пойдет о новой функции. Во время нескольких конференций C++ Russia мы обсуждали плохую работу списков инициализаторов. Есть ли планы по решению этой проблемы?
Бьярне: Мы пытаемся их немного улучшить. Мне бы хотелось знать больше о том, что люди думают об этих сбоях. Направьте их ко мне, это сильно поможет в работе. Списки инициализаторов работают не совсем так, как я задумывал. Их улучшали, однако, как по мне, улучшения не были улучшениями. Мы постепенно делали их менее склонными к выдаче ошибок, более мощными, более полезными. Думаю, мы продолжим работу в этом направлении. Если у кого-то есть реальные примеры плохой работы, было бы интересно узнать об этом больше: всегда сложно угадывать, что беспокоит людей. Нужно встречаться, обсуждать. Поэтому-то мне и не нравятся видеоконференции. Я не могу поговорить с вами до и после конференции, не могу узнать вашего мнения относительно не оговоренных проблем, не могу попытаться вам помочь, подкинуть какие-нибудь идеи. Живое общение очень важно, я очень скучаю по возможности встречаться с людьми.
Сергей П.: Мы тоже очень хотим проводить живые встречи.
Бьярне: Да, кстати, у вас в России есть комитет по стандартизации C++. Присоединяйтесь к нему. Вы сможете посещать встречи и использовать их как канал передачи ваших идей. Учтите, мне больше нравятся проблемы, чем их решения потому, что зная проблему, я могу разработать решение. А многие, в свою очередь, смотря на свою проблему, хотят увидеть конкретное решение. При этом проблемы у всех разные, сложно решать каждую из них. Нам нужно получить информацию о большом количестве проблем и работать над решением, которое бы подходило для решения множества задач.
Сергей П.: У рабочей группы в России есть сайт stdcpp.ru, который также является форумом, где можно обсудить свою проблему с другими участниками и проголосовать за то, чтобы ее обсудили позже в комитете. У нас в рабочей группе-21 три участника представляют вашу проблему. Если она наберет популярность, они могут помочь вам с подготовкой статьи. Такое уже случалось. В комитете уже прорабатывали предложения от сообщества, например, wide_int, которое поступило через сайт. Кстати, эту идею предложил студент, а не профессиональный разработчик. Позже он стал соавтором статьи. Сейчас этот вопрос обсуждается. Мы активно просим всех участвовать в работе, которая обычно доступна для публичного просмотра. Более того, мы организуем встречи в Москве и приглашаем принять в них участие.
Бьярне: Это великолепно. Однако, я бы хотел попросить вас напоминать людям, что большинство языков программирования умерли. У нас было как минимум 10 000 языков, которые полностью удовлетворяли своих создателей. Они в итоге исчезли. Успех языка программирования не равен победе в конкурсе популярности. Нужно думать о большем сообществе. Нужно понимать, что с вашей проблемой столкнулись и программисты в Калифорнии, Ухани, Бангалоре и других местах. Ваша проблема может быть такой же проблемой и в других сферах применения языка. Более того, многие пишут на C и C++ потому, что это старые языки. Код, написанный 10 лет назад, все еще исполняется. Это дает людям уверенность, что код, который они пишут сегодня, будет исполняться через 10 лет. Многие пользователи, большие компании думают о выживании своего кода. Поэтому я делаю акцент на совместимости. Мы не можем прийти к улучшениям ценой нарушения совместимости. Миллионы сегодня хотят и новых фишек, и избавления от старья, и чтобы код работал.
Инструменты Бьярне
Сергей Ф.: Справедливо. Какими инструментами вы обычно пользуетесь? Вы пишете программы?
Бьярне: Пишу программы каждый день. У меня есть два набора инструментов. У меня два экрана. Один — от компьютера на Linux, иногда я пользуюсь кластером Linux, там GCC, система сборки и прочее. Второй — компьютер на Windows, там у меня Visual Studio и остальная мелочь. Я говорю мелочь, но компьютеры не маленькие — в последнем установлен i7. Я еще пользовался Mac, но мне никак не удавалось продуктивно работать с тремя разными системами, поэтому остался с двумя. Как по мне, пользоваться одной системой очень опасно для программиста и особенно дизайнера языка. Вам кажется, что эти инструменты — отличный выбор, с ними все в порядке и все должны ими пользоваться. Опасный подход.
Сергей Ф.: Если у вас есть кластер на Linux, почему вы не используете систему непрерывной интеграции, чтобы пользоваться разными наборами инструментов?
Бьярне: Может, я и использую, это корпоративные машины. Кстати, компьютер на Windows может взаимодействовать с миром без каких-либо проблем с безопасностью. Я работаю в банке. Многие хотели бы взломать банк, в конце концов, там лежат деньги, поэтому о безопасности нужно думать. Если же мне взломают персональный компьютер, я расстроюсь, но миру это не нанесет серьезного ущерба.
Есть еще одна машина, на которой я могу запустить любую систему, могу загружать в нее. На ней запускается компилятор от Microsoft, Clang и GCC. Ладно, не буду продолжать. Хотелось бы еще машину на Intel и еще парочку, но поддерживать их в работе — все равно что устроиться на полную ставку. У меня помимо этого есть работа, преподавание и C++.
Сергей П.: Вопрос, наверное, заключался немного в другом. Пользуетесь ли вы, например, AddressSanitizer, статическим анализатором и остальными инструментами? Как разработчик ПО, пользуетесь ли вы отладчиком? Проводите ли вы отладку своего ПО? Используете ли вы GDB или аналог, или Godbolt?
Бьярне: Да, я часто использую Godbolt. Еще я использую статический анализатор от Microsoft. Он работает по Core Guidelines, я не использую clang-tidy, поскольку не рассчитан на работу в области моих интересов. Отладчиками я пользуюсь нечасто. Есть cppreference, этого достаточно.
Последние проекты
Сергей П.: Если не секрет, не могли бы вы рассказать, над чем вы работаете в последние 2–3 года?
Бьярне: Моя работа видна по моим предложениям, вносимым в комитет по стандартизации — я сильно занят подготовкой C++20. Вся работа излагается довольно подробно. Модули, сопрограммы, концепции. Также я работал с заказчиками, но там не сложилось. Кроме того, я писал статьи об истории развития языка в последние 15 лет, о направлении его развития. Также я постоянно работаю над ключевыми рекомендациями. Участвую во встречах с представителями Microsoft, Facebook, Red Hat.
Я не могу много рассказать о работе в банке, но в целом, это обычная работа с распределенной системой, похожая на то, чем я занимался последние 40 лет. В банковской сфере существуют серьезные ограничения по надежности и производительности, отчего работать интереснее. В бытность учёным я считал микросекунды. Сейчас приходится считать наносекунды, но суть работы не меняется — код стареет, его необходимо обновлять. Все как везде.
Уже совсем скоро, 11-14 ноября, в онлайне пройдёт новая C++ Russia. В её программе тоже есть два интервью: с Мэттом Годболтом (вы же наверняка пользуетесь golbolt.org?) и с Тайтусом Уинтерсом (о том, стоит ли сломать обратную совместимость C++ во имя производительности). А кроме интервью, будут доклады на самые разные темы: современный CMake, SIMD-инструкции, лямбды… В общем, если это интервью было вам интересным — на новой конференции наверняка тоже найдёте много интересного.