Pull to refresh

Comments 97

Его троллфейс так и говорит: никогда!
Использовать emacs/vim/gdb — это как пытаться каменными инструментами сделать колесо
эх… а я надеялся, что он то уж точно знает, когда будут модули
А вот лично меня устраивает деление на заголовочники и cpp файлы, мне нравится препроцессор и абсолютно не понятны пассажи к переделки этих удобных вещей.
деление на заголовочники и cpp файлы это еще не самое страшное зло. Самое страшное зло — это отсутствие такого деления в свете шаблонов)))
Время компиляции вас тоже устраивает?
Человек просто не пробовал скомпилить большой проект, больше миллиона строк на Delphi и на С++ =) Я обеими руками за модули, и уже смотрел как их в Clang реализовали.

p.s. по-моим прикидкам «на глаз», разница в скорости сборки в сотни, если не тысячи раз.
Так, для справки:
Наши проекты на Delphi (1.5 и 1.8 млн строк) компилируются за 38 и 18с соответственно (разница из-за разницы в сложности связей) на холодном кеше, и это полный ребилд. Если компилировать только измененные модули + линковка, вообще мгновенно, секунд 5-7.
Delphi компилятор на порядок быстрее любого сишного, уж извините
Это интересно, расскажите подробнее, в чём причины такой высокой скорости компиляции Delphi? Сам язык значительно проще или есть и другие существенные факторы?
Сам язык. Тот же Паскаль, а он изначально под однопроходку создавался. Ну и откровенно говоря, оптимизатор у него слабоват.
Из-за однопроходности в delphi/lazarus например нельзя сделать так:
type TFunctionChain = function(const value: String): TFunctionChain;
а если сделать по другому, но могут начаться проблемы с компиляторами
  PFunctionChain = ^TFunctionChain;
  TFunctionChain = function(const value: String): PFunctionChain;
Это скомпилируется
Но если вы попытаетесь определить такую функцию:
function functionChain(const value: String): PFunctionChain;
  begin
    writeLn(value);
    result:= @functionChain;
  end;
то в lazarus это скорее всего вообще не соберется
а в delphi если и соберется то может свалится при выполнении
да и код использования будет какой-то не такой:
functionChain('1')^('2')^('3');
чтобы сделать код использования таким:
functionChain('1')('2')('3');
можно попытаться объявить функцию как возвращающую TFunctionChain а не PFunctionChain
function functionChain(const value: String): TFunctionChain;
но тогда может не скомпилироваться код
functionChain('1')('2')('3')
или
functionChain('1')^('2')^('3');
но при этом возможно сможет скомпилироваться код:
functionChain('1')^('2')('3');
На некоторых версиях это может работать, даже на совсем древних.
Конечно. Но сам случай — не самый распространенный, мягко говоря.
а в delphi если и соберется то может свалится при выполнении

Для интереса прогнал — нет, не упадет.

functionChain('1')('2')('3') — очень вырвиглазный код. Я понимаю, что пример синтетический, но если бы увидел в реальной жизни что-то подобное, с последовательным вызовом через указатели, то сказал бы, что код дурно пахнет.
конечно
это синтетический пример для демонстрации проблем однопроходного компилятора
Но вообще-то ничего особо страшного тут нет — в C++ никто не удивится функтору, возвращающему функтор
Страшного нет, просто проблема надуманная. В конце концов, можно typecast ами обойтись. Но (1)(2)(3) — «веселый» код, особенно в отладке.

Кстати, интересно, как эта проблема решена для классов:
type
  TAbc = class;
...
...
  TDef = class
  public
    function Xyz(): TAbc;
  end;
..
..
  TAbc = class
  ...
  ...
 end;
Да, из-за однопроходности компилятора необходима специальная синтаксическая возможность для обхода ограничений однопроходности. Это forward реализации функций, допустимость обработки указателей на тип до определения самого типа, отделение интерфейсов от реализации и вот такое специальное опережающее описание класса. Ну и стоит ли овчинка однопроходности выделки такой ценой?
допустимость обработки указателей на тип до определения самого типа

Это нормально. Указатель приводится к чему угодно.

отделение интерфейсов от реализации

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

Ну и стоит ли овчинка однопроходности выделки такой ценой?

Конечно. 99% случаев покрывается, а 1%м вроде синтетического примера выше можно поступиться.
допустимость обработки указателей на тип до определения самого типа
Это нормально. Указатель приводится к чему угодно.
Это ужасающе в плане придумывания костылей.
Почему forward-определения указателя недостаточно для класса?
Потому что класс и так передаётся только как ссылка.
Поэтому мы сделаем новый тип forward определений для класса.
И для интерфейсов тоже.
Но функция тоже ссылочный тип. А что с функциями?
Да и фиг с ними — добавлять еще одни костыли глупо, а сделать по-нормальному — сложно.
отделение интерфейсов от реализации
Это тоже замечательно — мне нравится такое разделение. Напротив, мешанина — нечитабельна.
Да уже не осталось языков которые требуют такого отделения. Это всё анахронизмы, как и секция var.
Конечно. 99% случаев покрывается, а 1%м вроде синтетического примера выше можно поступиться.
Если какая-то простая конструкция из-за какой-то несусветной причины не может быть описана на языке — то это очень говорит о продуманности такого языка, тем более языка, претендующего на академичность.
Это ужасающе в плане придумывания костылей.

То же, что и с Си — мол, много способов «выстрелить в ногу». Хочешь — стреляешь, не хочешь — делаешь нормально.

Почему forward-определения указателя недостаточно для класса?
Потому что класс и так передаётся только как ссылка.

Этот обрубок — это и есть forward, просто по-другому описан, в отличие от процедур.

Но функция тоже ссылочный тип. А что с функциями?

Ну вот и ответ, в принципе: с классами это было людям нужно — добавили способ forward описания. С функциями — не было нужно.

Да уже не осталось языков которые требуют такого отделения. Это всё анахронизмы, как и секция var.

И? Мне лично так нравится больше: читаемость лучше. С секцией var проблем не вижу: мне нравится, когда код структурирован. Тут — объявления, тут — код. Учитывая, что хорошим тоном является разбиение процедур, секция var так и так в поле видимости, плюс/минус. Если функция — простыня на 3 экрана, тогда, да, объявлять по месту лучше. Но это уже не особо хорошее оформление кода.

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

Да это не простая конструкция, это надуманная проблема, а не реальный код. Не представляю, чтобы кто-то вызывал цепочку таким образом — попробуй отладь потом такой код.
А, да, насчет академичности: в оригинальном Паскале не было ссылок и процедурных типов.
Вроде как в виртовском паскале есть параметры типа процедура, но нет переменных типа процедура (короткая дискуссия на эту тему).
То же, что и с Си — мол, много способов «выстрелить в ногу». Хочешь — стреляешь, не хочешь — делаешь нормально.
Я имел в виду синтаксические костыли.
Ну вот и ответ, в принципе: с классами это было людям нужно — добавили способ forward описания. С функциями — не было нужно.
Это называется — отсутствие общего подхода. Если бы язык был как-то стандартизирован, такой фигни бы не было. А так — язык одного актёра разработчика.
С секцией var проблем не вижу: мне нравится, когда код структурирован. Тут — объявления, тут — код.
Вам ничто не мешает писать так и в C++ и игнорировать удобство RAII. Но это же не значит что надо превозносить такое искусственное ограничение языка.
попробуй отладь потом такой код
ограничения отладчика конечно важны, но тоже не являются непреодолимым барьером.
Например я лет 10 назад перешёл с idea на eclipse потому что у тогдашней idea были проблемы с отладкой анонимных классов. В случае же delphi не получится сменить ide или компилятор, поскольку, увы, альтернатив нет.
Это называется — отсутствие общего подхода. Если бы язык был как-то стандартизирован, такой фигни бы не было. А так — язык одного актёра разработчика.

Почему же? В случае класса нам нужна подсказка компилятору о типе данных, а в случае функции — нет. Это разные области: в одном случае — тип данных, в другом — объявление процедуры. Поэтому и синтаксический подход различен. Это только человеку кажется «мы же и там и там на что-то далее по тексту ссылаемся». Вот если бы подсказка для процедурного типа была бы реализована иначе, чем для типа «класс», тогда вы были бы правы. Но такой подсказки нет вовсе, поэтому про неоднородность говорить не приходится.

Вам ничто не мешает писать так и в C++ и игнорировать удобство RAII. Но это же не значит что надо превозносить такое искусственное ограничение языка.

Не мешает. Я просто говорю, что это не проблема. Вообще. Искусственное ограничение? Тогда любое синтаксическое правило — искусственное ограничение. Можно точно так же сказать, например, что перечисление включаемых модулей (или include'ы заголовков в C/C++) — тоже искусственное ограничение. Можно сказать, что, например, необходимость применения break'а в switch'е — искусственное ограничение, вызванное реализацией таблицы переходов. Или необходимость в цикле с условием всегда использовать while.

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

Не в ограничении отладчика дело, просто сама конструкция нечитаема. Мне, например, не нравится фактически самомодифицирующийся код.

В случае же delphi не получится сменить ide или компилятор, поскольку, увы, альтернатив нет.

Во-первых, тот же lazarus.
Во-вторых… а и не надо. За 6 лет, что я пишу на delphi по работе, единственное ограничение, которое изредка досаждает — отсутствие полноценных шаблонов. И то, частично это реализовано.
Никто не спорит — те же плюсы намного мощнее, универсальнее и пр. Я лишь говорю, что готов поступиться 1% функционала за ту же быструю компиляцию и гарантированную структурированность (=лучшую читаемость) программы.
Поэтому и синтаксический подход различен.
Это костыли а не подход.
В одних случаях указатель автоматически разъименовывается, в других нет, в третьих возникает конфликт и для получения указателя надо использовать @@ вместо @ и все это зависит от параметров компиляции и версии компилятора.

break'а в switch'е — искусственное ограничение, вызванное реализацией таблицы переходов
если бы в switch не было возможности перехода из одного case в следующий, то чтобы съемулировать такую возможность пришлось бы использовать goto или разделение на функции

За 6 лет, что я пишу на delphi по работе, единственное ограничение, которое изредка досаждает — отсутствие полноценных шаблонов. И то, частично это реализовано.
Шаблоны в pascal ещё 25 лет назад эмулировались с помощью include.

А вот что меня сейчас досаждает — то что generic-и в java никогда не будут иметь возможностей шаблонов C++, поэтому приходится заменять статическую типизацию на динамическую выдумывая как бы при этом сохранить типобезопасность.

гарантированную структурированность (=лучшую читаемость)
Ничто не мешает писать структурировано и читабельно на языке в котором много плюшек.
Не хотите — ну не пользуйтесь всеми плюшками. Но не говорите за всех.
Это костыли а не подход.

Это разный подход, а не костыль. Разные конструкции — разные подходы. Объявление процедуры — одно, тип данных — совсем другое. Вас же не удивляет, что класс объявляется при помощи class {, а процедура — при помощи void abc () {?

если бы в switch не было возможности перехода из одного case в следующий, то чтобы съемулировать такую возможность пришлось бы использовать goto или разделение на функции

Это лишь один пример «искусственного ограничения».

Шаблоны в pascal ещё 25 лет назад эмулировались с помощью include.

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

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

Не мешает. Я просто говорю, что блоки var — не стоящая внимания «проблема».

Не хотите — ну не пользуйтесь всеми плюшками. Но не говорите за всех.

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

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

Вот что пишут в Интернете:

One reason why Delphi may be faster to compile than C++ is that Delphi
has a proper module system, whereas C++ still uses the old #include
preprocessor hack. The old #include hack has the drawbacks that the
meaning of each header file included may depend on what macros are in
scope at that point. So the effect of including header files in a
different order might be different. This makes precompilation of
header files much more difficult, complicated, and ineffective than
for Turbo Pascal units. As a result, C++ compilers tend to parse the
headers each time they are read, rather than precompiling them.

Мой кривой перевод:
Одна из причин, почему компилятор Delphi может быть быстрее компилятора С в том, что Delphi имеет продуманную систему модулей, в то время как C использует «старинный» хак с директивой Include. Использование include приводит к тому, что значение каждого заголовочного файла может трактоваться по-разному в зависимости от того, какие макросы находятся сейчас находятся в области видимости. Это делает прекомпиляцию .h файлов гораздо более сложной и трудозатратной задачей по сравнению с компиляцией модулей в Паскале/Delphi. В результате C++ компиляторы как правило выполняют парсинг заголовочных файлов каждый раз когда эти файлы прочитываются, вместо того чтобы прекомпилировать их заранее.
Конкретно эту проблему можно обойти активно используя прекомпилированные хидеры. Помнится, у нас на проекте таким способом удалось ускорить полный ребилд в 10 раз с 20 минут до 2-х.
Но это костыль, который у каждого компилятора сделан по своему, и к тому же нарушает читабельность.
Разделение на библиотеки, precompiled headers, меньше буста в на каждый чих, многопоточная компиляция…
… да и хабр можно почитать пока компиляемся!
иногда приходится переписывать медленные части веб-приложений на с++
и по правде говоря, из-за указанных минусов (отсутствие менеджера пакетов, модулей, сложная сборка и тд) пробую переходить на Rust
Пока нравится, но к сожалению, пока слабая инфраструктура и неуверен «выстрелит» ли язык или «затухнет»
UFO just landed and posted this here
Есть такой холивар, что Qt — это просто gui модули и больше нигде использовать его нельзя, т.к. медленно, много, непонятно и прочее. Настоящие С++ программисты ядра приложений пишут используя только boost, а Qt ни в коем случае нельзя.
Про IDE Qt Creator тоже ни слова. Я вот два года в нем проработал и сейчас просто в шоке от Visual Studio 2012. Она даже с платными плагинами не догоняет Creator по возможностям рефакторинга и поддержки автодополнения, да и лагает блин периодически. Ну и естественно у креатора есть Qt специфические фичи, которых в студии вообще никогда не будет.

С другой стороны автор специализируется на С++ библиотеках без лишних зависимостей, зачем ему Qt.
По поводу Qt Creator — пытался работать с ним, но никак не ужился с отсутствием нормального дебаггера. Именно из-за шикарного дебаггера — использую только студию (рефакторинг — с плагинами, автодополнение — в 13й — очень даже не плохо). Ну а вне Windows — Qt Creator единственная IDE
Не понимаю в чем проблема, дебаггер в Qt Creator можно выставить такой же виндовый как в студии.

Тест на работу автодополнения — что найдется если в студии, если попробывать найти все ссылки на переменную? У меня почти всегда находит все вхождения литерала по решению, что делает невозможным даже тупо переименование переменной. Можно ли на лету менять сигнатуру методов и функций (чтобы автоматом менялось и объявление)? Можно ли вставлять объявления от выбранных виртуальных методов в наследуемом классе?

«такой же виндовый как в студии.».
Вы чуть-чуть неправы. Сам пользуюсь QtC. В нем можно выбрать 3 дебаггера: CDB (Microsoft Console Debugger,) GDB, LLDB. В Visual Studio не используется CDB! там отладчик встроен в саму среду и использует dll-ки компилятора. У него общая модель кода с компилятором=)

А про автодополнение в студии — обычно люди без VisualAssist ее не используют, стандартный функционал уж очень урезанный =) Я кучу дополнений ставил на 2010, чтобы приблизить ее к удобству QtC.
«Можно ли на лету менять сигнатуру методов и функций » — в VA да. там так и работает.
а про выбранные виртуальные методы — раньше не было ;) сейчас не знаю. Очень клевая вещь, но не самая частая, я не каждый день ее юзаю.

К слову, попробуйте объявить vector a;
a[1].Method();
И затем переименовать метод в QtC и студии. в QtC сработает только с Clang code model. в студии — на отлично =)
Но тем не менее, Creator — наше все и я его люблю куда больше и предан ему!

Просто небольшое замечание по объективности.
Так естественно я поставил VisualAssist и несколько других дополнений, перенос строки например, который тоже работает хуже, чем в Qt Creator — там строка подстраивается под выравнивание блока, в VS нет.

Как в VA менять на лету? Я знаю только, что можно поменять сигнатуру через вызов специального диалогового окна, а если ты по ходу поменял сигнатуру функции, без вызова специального метода, то менять её придется в ручную в объявлении. В Qt Creator есть хот кей для этого, он сам по уже изменной сигнатуре подправит объявление, и кстати корректно переименует параметры метода или функции везде, где они использовались.

Не совсем понял что предлагаете сделать с вектором. Отнаследоваться от вектора, объявить метод и потом его переименовать?
хабрапарсер угловые скобки поел) нет, не наследоваться вектор с типом SomeClass я написал. Модель кода в QtC не понимает тип элементов вектора, и дополнение и рефакторинг не работают. Даже в 3.5.
Поэкспериментировал. Оказывается, с std::vector действительно не понимает, а вот с QVector (и прочими qt-шными контейнерами) понимает прекрасно. В целом действительно модель кода слабовата, но работает она быстро и для многих вещей ее хватает.
Время попробовать Resharper C++. Он очень ок.
Тест на работу автодополнения

Все действия в дальнейшем с использованием VA
найти все ссылки на переменную

Выделяем переменную shift + alt + f и VA находит все места где используется эта переменная.
переименование переменной

shift + alt + q выбрать пункт rename
менять сигнатуру методов и функций

shift + alt + q выбрать пункт change signature
Можно ли вставлять объявления от выбранных виртуальных методов в наследуемом классе?

shift + alt + q выбрать пункт Implement Virtual Methods

Ещё что-то нужно?

Вынос метода — есть, вставка инклудов — есть, создание переменных — есть, имплементация методов\ функций — есть, Переименование файлов — есть, снипеты, скобки по выделенному — есть, поиск и переход — есть, показать объявление внутри маленького окна — есть (alt + F12 это даже фича студии а не VA)
shift + alt + f

Проверил только что, взял первый попавшийся ашник и захотел найти все ссылки на параметр в методе. Нашел только ссылку в самом ашнике, т.е. ничего. Но в теле функии таки нашел, и не по всему солюшену, а именно где ссылка на объект. На много лучше, чем find all reference.
shift + alt + q

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

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

имплементация методов\ функций — есть

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

Странно, у меня находит везде, ещё ни разу проблем не было, даже на больших проектах в несколько М строк, какой версией пользуетесь? И на всякий случай, вы ашник открыли в рамках проекта, или просто как отдельный файл?
version 10.9.2068.0 built 2015.06.09

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

Анализировать студия тоже очень любит. По F2 иногда тупит на пару минут, что то там индексирует.
Кстати, а вот извлечь функцию тоже в VA есть? То, что я видел в студии извлекает метод, при этом не пытается даже завести возвращаемые из функции параметры — всегда void результатом ставит, а параметры функции только входные. Это норм для студии и VA?
Кстати, а вот извлечь функцию тоже в VA есть?

Есть
при этом не пытается даже завести возвращаемые из функции параметры

Всё зависит от того что в коде который выделяешь.
Это понятно, что зависит. Просто иного я еще не видел.
UFO just landed and posted this here
Ну зачем столько сарказма? Когда используешь cdb (другие не пробовал) из-под QtCreator-а, лично у меня — он подвисает очень часто и, по сравнению со встроенным Visual Studio Debugger-ом — всё продвигается медленнее. Просмотр переменных в QtCreator-е просто ад и ужас, особенно, если это обычные строки. Watch-окна, вроде как, нет (с удобными штуками такими как @ err,hr). Окна потоков/подключённых процессов так же как и окна пам'яти/call stack-а — удобнее в студии. Такой штуки как Autos в QtCreator-е, если я не ошибаюсь, вообще нет (так же как и дизасемблера ?). Коннектиться к удалённому процесу — намного проще, если ещё и к vmware-виртуалке (удобный плагин, всё в один клик). Как подключить KD — я так и не нашёл (хотя, признаюсь, гуглил не больше 2х минут).

Дизасм? дизасм кода в отладчике в QtC есть. про KD — не понял =)
Да, дебаггер студии не использует CDB, а использует либы и модель кода от компилятора. Он встроен в ИДЕ. см. коммент мой выше по ветке.
UFO just landed and posted this here
Я такого же мнения о Qt, но холивар то есть.
Я бы в холивар подкинул тот факт, что Qt не потащишь в средний embedded, где лимиты памяти 4-8 Мб. а вот stl и boost — да =)
QtCore+Network урезанные флагами у меня добавляют под арм сборку больше 2Мб, а boost — всего 300 Кб. Ну, понятное дело, что подмножество используемых фич очень важно. Но даже просто QString заюзать — очень много за собой тянет.

Вот для десктопов — я согласен, и для консольных, и для сетевых приложений лучше не придумать. Контейнеры ничуть не хуже stl.
Работал на плате с 8 мб памяти. Из них образ системы вместе с Qt занимал 4 мб. Возможно вы не использовали флаг оптимизации для уменьшения размера бинарников.
У меня только linux busybox 3mb отъедает. Так что это вряд ли получится.
Даже с clang code model автодополнение и контекстные подсказки Qt Creator сливают, к сожалению, студии, когда дело доходит до более-менее сложных шаблонов
Вот что на ваш вопрос ответил Эрик:
Я признаюсь, что у меня нет опыта использования Qt. Если бы я занимался разработкой приложений, мне бы наверняка пригодилась её функциональность, но ничего не могу сказать про неё с точки зрения проектирования.

Оригинал
I confess that I have no experience using Qt. If I were an application developer, I'm sure I would find the functionality in Qt useful, but I can't comment on its design.
UFO just landed and posted this here
Кстати, в эту пятницу Эрик выступает с keynotes на конференции C++ Siberia в Новосибирске.
Но, если бы мне нужно было выбрать всего одну штуку, которая больше всего повлияла бы на C++, я бы выбрал простой, надёжный и мощный менеджер пакетов.


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

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

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

Мне кажется, для её решения, возможно нужен гигант вроде Майкрософта, Гугла (или Яндекса?). Это сложная, большая, занудная и не приносящая славы задача того типа, которыми не любят заниматься волонтёры.


А есть какие-нибудь периодические открытые тусовки в Яндексе, куда можно прийти и поговорить о судьбах С++? Я в своё время через знакомого пытался выйти на людей из Яндекса, но дело забуксовало.
Если кто-нибудь хочет принять любое участие в работе над менеджером пакетов — был бы очень рад. Обсуждение: советы, пожелания, угрозы — тоже приветствуются.

Если я правильно понял Эрика он сожалел о судьбе bii code. Который вроде бы почти смог, но ресурсов не хватило. Они открыли код и вроде бы их собирались интегрировать в CLIon.

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


Так на встречах C++ User Group периодически выступают ребята из Яндекса. Плюс, у Яндекса есть C++ Party
он сожалел о судьбе bii code

Кстати, а что случилось с bii code? На сайте у них вроде ничего такого не написано…
Вот здесь они все пишут. У них именно бизнес не получилось завести. То есть, они рассчитывали получать с этого хоть какой-то профит. Однако, не смогли набрать достаточное количество корпоративных пользователей.
Спасибо за наводку на bii code. Очень ценно было почитать о том, как ребята это сделали.

вроде бы их собирались интегрировать в CLIon


На их сайте написано что Biicode uses CMake to configure and build your projects and it is compatible with many IDEs and version control systems. Тобишь, вроде, со всеми может использоваться через консоль. В CLion bii code, видать, будет встроен в интерфейс IDE.

Так на встречах C++ User Group периодически выступают ребята из Яндекса


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

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

Я советую посмотреть в сторону clang/LLVM, которые можно использовать как бакенд для своих задач. При этом компилятор предоставляет все средства для анализа, но без лютого геморроя.
Парсер нужен для генерации pimpl-обёрток для классов библиотек. Дело в том, что, в отличие от bii code, в моей системе решения зависимостей, зависимости подтягиваются в виде скомпилированных библиотек (статических или динамических) + хедеров, а не исходников с реализациями классов. Для универсальности хедеров (и, соответственно, возможности простого переключения между статической и динамической библиотекой) хотелось использовать идиому pimpl.

Насчёт clang — интересно. Нашёл о нём статью на хабре, там как раз тема использования в качестве кодогенератора обсуждалась. Если забуксую со своим парсером — гляну.
Вы совершенно точно зароетесь насмерть с парсингом. В C++ построить фактическое AST возможно только с учетом семантики языка и только GLR парсером.

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

Помимо этого существует просто кретинистически много разных синтаксических конструкций и правил парсинга, которые мы в 99% времени не встречаем. Ну например, ключевое слово template может встречаться и внутри выражений. Не говоря уже про накие няшности как foo->Bar::baz(), foo->~Foo() и (object->*method)()

Даже просто воскурить стандарт и написать по нему правила разбора это работа минимум на год. Но… зачем? Если есть готовый компилятор, который предоставляет все эти возможности и гарантированно будет поддерживаться и содержать минимум ошибок.
Да. Почитал про clang — скорее всего, всё же его использую. А парсинг плюсов на своём парсере тогда чуть отложу — сделаю когда время будет.

Даже просто воскурить стандарт и написать по нему правила разбора это работа минимум на год.


Кстати, начинал эту работу. Осилил до этого момента где-то одну десятую часть: идентификаторы, все литералы, декларации классов и где-то половину вещей, связанных с шаблонами. У меня парсер хавает не БНФ, а представление разбора в виде графа (мне такое представление кажется более наглядным) — поэтому осмыслял путём перевода БНФ из стандарта в представление в виде графа.
Осмыслял путём перевода БНФ из стандарта в представление в виде графа.

Это похоже на подход применяемый в ANTLR парсере. LL(*) если я правильно помню. В отличие от GLR/LR, это разбор «сверху вниз», а не «снизу вверх».
Ух ты, какую я мудрёную штуку сделал, оказывается. Не понял половины слов, пошёл гуглить.
Еще пару слов о парсерах. Проект KDevelop на данный момент использует кастомный парсер C++ для целей code assist, refactoring и syntax highlight. Так вот разработчики говорят что их парсер это «50 тысяч строк глючного, сложно поддерживаемого и трудно расширяемого кода», который им приходится тащить на себе и развивать от версии к версии. А ведь им приходится еще и тащить парсинг препроцессора на на уровне синтаксиса, что тоже добавляет геморроя. С большой вероятностью, вам пришлось бы повторить этот ад у себя.

К счастью, уже существует проект и форк по пересаживанию KDevelop на парсер clang. И я сам его жду с нетерпением, потому что работа с шаблонами будет еще проще и полнее чем сейчас.
А за счёт чего clang умудрился избежать всех этих проблем? Его позже разрабатывали?
Да, clang писался позже, с учетом опыта и ошибок предшественников (GCC), так что архитектура и качество кода у него лучше. И он сразу был ориентирован на наличие API для встраивания в другие проекты, а не только использование в качестве отдельного компилятора. Но он всё равно сложный, потому что сам язык C++ сложный, и от этого никуда не деться. Просто поддерживать (и разрабатывать, ведь C++ на месте не стоит) один парсер гораздо проще, чем каждый проект (IDE) будет пытаться делать это самостоятельно. Ну и использование libclang гарантирует, что ваша программа будет понимать код точно также, как это делает настоящий компилятор, что хорошо.
Посмотрите ещё на проект CastXML. github.com/CastXML/CastXML
Это форк GCCXML. Строит AST в XML формате. Использует Clang.
Спасибо за наводку на библиотеку. Хотя в моём случаи формирование полного AST в виде XML это лишние. У меня задача простая: считать информацию о классах и сформировать для них классы-обёртки, реализующие идиому pimpl. Сделать это желательно за минимальное время. В идеале — с использованием подхода вроде SAX для XML (Clang, вроде, позволяет что-то такое делать судя по беглому осмотру).

П.С.: Хотя сохранение AST в XML может быть способом сохранения информации для инкрементального билда. В этом смысле CastXML действительно может быть полезен.
для генерации pimpl-обёрток для классов библиотек

Ваш менеджер пакетов будет подменять хедеры?
Boost или другие header-only библиотеки им можно будет подключить? Если нет — зачем он нужен?
Можно будет. Кодогенератор будет копировать шаблонозависимый контекст напрямую. Обёртки же будут формироваться для свободного от шаблонов контекста.
Про свой парсер, кстати, статью планирую на хабру написать. Не подскажете какую лицензию можно поставить на исходники при публикации чернового демонстрационного кода библиотеки — чтобы запретить пока использование сорцов в любых публикуемых проектах? (Вопрос по библиотеке на Тостере).
Нельзя просто взять и запретить то, что однажды было выложено в сеть.

Зачем? Если вы хотите поделиться проектом с сообществом, то выкладывайте под открытыми лицензиями и не мучайтесь. Не стоит переоценивать желание людей кидаться на полуготовые исходники и красть их. Даже вполне себе оформленные проекты валяются на гитхабе годами и никакой активности не наблюдается.
Не стоит переоценивать желание людей кидаться на полуготовые исходники и красть их


Ага. Ну, ок. В принципе, можно. А конверсию затраченного на библиотеку времени можно будет как-нибудь погодя получить — хотя бы через те же пожертвования на проект если дело выгорит.
Если кто-нибудь хочет принять любое участие в работе над менеджером пакетов — был бы очень рад. Обсуждение: советы, пожелания, угрозы — тоже приветствуются.

Тут проблема вот в чем: чтобы сделать это действительно удобным нужно поставлять бинарники. И вот тут проблема, т.к. нужно одно из двух:
  • Или компилировать библиотечку всеми компиляторами × версиями компилятора × битность × другие настройки, что весьма накладно; или
  • Компилировать библиотеки на стороне клиента, что требует наличие подходящих билд-систем а также уйму свободного времени, т.к. компилировать какой-нть Boost (даже на RAM-диске и 32 процах) — процесс небыстрый, а вся суть пакетных менеджеров — чтобы быстро работало.

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

Насчет biicode — у них просто бизнес-модель не выстрелила, насколько я понимаю. Nuget для С++ кстати тоже не подарок.
Или компилировать библиотечку всеми компиляторами × версиями компилятора × битность × другие настройки, что весьма накладно


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

Поэтому верится что для этого существует некая некоммерческая ниша.


Почему обязательно некоммерческая? Можно создать магазин библиотек с гибкой настройкой лицензий: от полностью freeware с возможность изменения кода до платной для личного пользования. Вот тут ребята так пробуют зарабатывать (нашёл в процессе поиска на вопрос).
Так а собственно вопрос о настройках остается открытым. Например я библиотеки компилирую с поддержкой AVX, очевидно что для общего пользования так делать нельзя. Значит мы должны шипить везде неоптимизированные либы. А это печально. Еще есть битность, линковка к стандартной библиотеке (статическая или динамическая, многопоточная или нет), и куча всего.

Если делать это on demand, нужно фактически иметь виртуалки на все возможные компиляторы и операционные системы. Компиляторы и вообще системы эволюционируют, поэтому нужно держать целый зоопарк разных версий и настроек. Я не говорю про то что по перформансу это нехило так выходит, т.к. в С++ компиляция это болезненная операция. По памяти кстати тоже, т.к. буст например генерит гигов 10 всякого шлака.

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

Если делать это on demand, нужно фактически иметь виртуалки на все возможные компиляторы и операционные системы


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

П.С.: Кстати, такую систему распределённой сборки можно сделать даже более абстрактной, не только для сборки плюсов, но и для сборки чего угодно. Выйдет что-то вроде глобальной торрент-make системы.
Так это называется «поставить TeamCity у себя в конторе», не? Или вообще в сетевую шару залить. А хочется всем сделать хорошо.

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

1. Решатель зависимостей. Смотрит на то, какие модули должны поставляться с нашим модулем. Выполняет запрос ресурсов из репозитория модулей по заданным настройкам (полная информация о сборке: ось, компилятор, какие-то таги с пожеланиями от пользователя, и.т.д). В идеале должен изменять файл проекта для IDE, выставляя нужные флаги компиляции для линковки статических библиотек, и.т.д.
2. Репозиторий модулей. Возвращает скомпилированный в нужном виде модуль (на основе переданных настроек) — в виде статической или динамической библиотеки. Если модуля, собранного с нужными настройками нету — репозиторий пытается собрать у себя, а, если и это не возможно, загружает исходники к пользователю, собирает их на машине пользователя, после чего отсылает обратно на репозиторий чтобы все люди получать собранный модуль.

При этом, если проводить аналогию с миром Java, где есть ещё Spring для внедрения зависимостей, в С++ механизм внедрения зависимостей может использовать, условно говоря, статический полиморфизме, когда реализации функционала подходит по именам и вызовам из других модулей (аналог интерфейса), но при этом имеет другой корневой include.
отсылает обратно на репозиторий чтобы все люди получать собранный модуль

мне единственное интересно, как контролировать что то, что юзер залил, валидно? например, boost.mpi можно собрать относительно всяких разных MPI библиотек. или можно собрать с оптимизациями по AVX. и все, цикломатический взрыв или как его там…
я считаю что нужно чуть по-другому: общий репо можно делать только для сорцов, чтобы можно было скачать их локально – их, и конечно механизмы их компиляции. тут тоже адов ад: например, скачиваешь репо, а оно использует visual studio и только, и компилит под 32 бит, и в путях жестко прописаны папки, которых локально нет или в других местах лежат. вообщем, вопросов очень много. и в основном из-за того, что нет никакой бинарной совместимости.
я бы лично конечно перевел каждое репо на cmake. только это не всегда работает (см. например буст)
например, boost.mpi можно собрать относительно всяких разных MPI библиотек. или можно собрать с оптимизациями по AVX. и все, цикломатический взрыв или как его там…


В процессе работы я выяснил, что, например, g++ из minWG умеет собирать библиотеки с предекларированными классами и функциями, реализация которых может линковаться в процессе сборки приложения. Надеюсь, другие компиляторы такое тоже умеют. Если да — то проблема со сборкой одних библиотек относительно других и использование такой сборкой третьими библиотеками отпадает.

Да и потом — библиотеки не занимают так уж много места. Можно сделать очень грубую прикидку. Пусть пять мегабайт будет одна сборка (а они, надеюсь, будут меньше, я верю в микромодульную архитектуру приложений). Пусть для неё будет пять разных конфигураций, каждая будет иметь пять значений (там, оптимизации разные, и.т.д). Выходит 5*5*5=125 мегабайт на одну библиотеку. Итого — на один гигабайт влезет восемь библиотек. На террабайтный диск — восемьсот. Восемьсот разных библиотек… Это нормально.

я бы лично конечно перевел каждое репо на cmake


cmake может служить костяком для системы сборки. До того как я почитал про bii, зависимости у меня получались через метод getDependencies(DDepRequest &) плагина (плагин у меня был классом, сейчас решил отойти от этого — очень не гибкий код выходит). После прочтения инфы о bii я подумал описывать зависимости через комментарии, семантически связанные с инклудами (умеет ли такое clang?):

//! version: [>3], tags: [o1, win32]
#include "myLib"
Я бы предпочёл на его месте основанный на AST чистый макропроцессор


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

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


Подсел на на Eclipse ещё в универе. Выбрал его тогда по нескольким причинам. Во-первых, Eclipse написан на Java и, соответственно, кроссплатформенный. Во-вторых, он бесплатный для коммерческого использования. Сейчас понимаю что Eclipse чудовищен (особенно дебаггер, это просто ужас какой-то) и хочу перелезать на QT, который обладает достоинствами Eclipse и не обладает многими его недостатками.
Я выучил C++ студентом

Страуструп не выучил, а Эрик выучил ещё студентом :)
Обратил внимание о емаковимописателях.
Чаще допускаются ошибки, т.к. нормальная IDE подсказывает и подсвечивает. Компилируемых языков это не касается, но в скриптовых порой встречается не рабочий код просто открыв его в нормальной IDE, когда не все покрыто тестами, да. Или множество возможных не инициализированных переменных, весь код в подсветках, как на новый год, в нормальной IDE сразу видно. Ну и любят они ещё на сервере кодить. Не все, но большинство восхваляющих, с кем имел дело. Пусть Java IDE и тормозная, но она умнее и с этим инструментом пишешь лучше код.
Вы ошиблись тредом, вам сюда.

встречается не рабочий код просто открыв его в нормальной IDE

При работе в emacs можно спокойно запускать pylint или jslint не выходя из редактора, даже автоматически в фоновом режиме (flymake), как в IDE. Они находят кучу подобных ошибок.

Ну и любят они ещё на сервере кодить.

В большинстве случаев это не прихоть, а необходимость.
Спасибо за линк, почитаю :)
Да, Роман, знаю, что можно настроить раб. среду, а на деле ничего не настраивают(ну не все да:), да мне туда, не по теме написал.
Многие думают что в C++ есть только меташаблонное программирование — шаблоны, бусты, аликсандрески разные…
Есть еще и метамакросное. Даже на стандартном препроцессоре можно творить относительные чудеса.
Стандартный препроцессор можно заменить — видел и использовал варианты с интеграцией в него lua кода.
Стандартный пропроцессор можно эмулировать — flex c bisonом давние друзья многих маньяков в деле автогенерации кода.

Так что — те-кому-надо уже давно AST контролируют. Вопрос только зачем и почему.
Так что — те-кому-надо уже давно AST контролируют. Вопрос только зачем и почему.


Думаю, вопрос скорее в том насколько это удобно. В принципе, люди и на брейнфаке морской бой писали.
Sign up to leave a comment.