Комментарии 21
Как побороли страх перед стартом? :)
0
В комментариях к предыдущей статье упоминали Haxe.
Несмотря на то, что я большой поклонник haxe, идею все транспилировать в него и работать потом с исходкиками я тоже считаю несостоятельной.
Тем не менее, мне кажется, он мог быть вам полезен. В первую очередь потому, что сам дизайн языка и его std во многом продиктован переносимостью на различные языки, а haxe генерирует вполне читаемые исходники на очень разноплановых языках.
Кроме того, помимо «работать везде», «эффективность» тоже учитывается. Поэтому с равным успехом можно писать, используя std и получать рабочий код на всех платформах, а можно писать свои обертки для платформенных реализаций и иметь родную производительность без оверхэда на целевой платформе. Этому способствуют такие штуки, как экстерны, в теле которых можно писать инлайн-методы, достаточно уникальная концепция абстрактов, поддержка меты синтаксисом языка и система макро-апи, позволяющая жонглировать AST наравне с рослином.
Вишенкой на торте можно добавить реализацию lsp компилятором, что позволяет резолвить сгенерированное макросами внутри IDE. Кроме того, есть инструменты для дебага и профайлинга на ряде платформ, в том числе на cpp.
Недавно обсуждали возможности в другой теме про транспиляцию.
По поводу транспиляции в cpp, на ютубе есть несколько докладов от Hugh Sanderson, автора cpp таргета. Может быть его опыт будет вам интересен – искать по слову hxcpp.
Мне кажется, можно было бы попробовать на небольших модулях/проектах – все-таки, это уже готовое решение, которое позволяет из одной кодовой базы получать библиотеки для чистого c, .net, jvm-байткод и исходники на всех этих языках. Python, PHP и JS тоже готовы из коробки.
Поэтому, вопрос: смотрели ли вы на Haxe, может нашли для себя какие-то интересные решения, или просто прошли мимо?
Несмотря на то, что я большой поклонник haxe, идею все транспилировать в него и работать потом с исходкиками я тоже считаю несостоятельной.
Тем не менее, мне кажется, он мог быть вам полезен. В первую очередь потому, что сам дизайн языка и его std во многом продиктован переносимостью на различные языки, а haxe генерирует вполне читаемые исходники на очень разноплановых языках.
Кроме того, помимо «работать везде», «эффективность» тоже учитывается. Поэтому с равным успехом можно писать, используя std и получать рабочий код на всех платформах, а можно писать свои обертки для платформенных реализаций и иметь родную производительность без оверхэда на целевой платформе. Этому способствуют такие штуки, как экстерны, в теле которых можно писать инлайн-методы, достаточно уникальная концепция абстрактов, поддержка меты синтаксисом языка и система макро-апи, позволяющая жонглировать AST наравне с рослином.
Вишенкой на торте можно добавить реализацию lsp компилятором, что позволяет резолвить сгенерированное макросами внутри IDE. Кроме того, есть инструменты для дебага и профайлинга на ряде платформ, в том числе на cpp.
Недавно обсуждали возможности в другой теме про транспиляцию.
По поводу транспиляции в cpp, на ютубе есть несколько докладов от Hugh Sanderson, автора cpp таргета. Может быть его опыт будет вам интересен – искать по слову hxcpp.
Мне кажется, можно было бы попробовать на небольших модулях/проектах – все-таки, это уже готовое решение, которое позволяет из одной кодовой базы получать библиотеки для чистого c, .net, jvm-байткод и исходники на всех этих языках. Python, PHP и JS тоже готовы из коробки.
Поэтому, вопрос: смотрели ли вы на Haxe, может нашли для себя какие-то интересные решения, или просто прошли мимо?
+3
Добрый день. По большей части прошли мимо, но аргументы, чтобы пройти мимо, у нас есть. Сейчас коротко перечислю.
Во-первых, всё упирается в объём работы. По сути, нужно портировать (не важно, единовременно или в автоматическом режиме) десятки миллионов строк наших проектов на Haxe для того, чтобы им можно было пользоваться. Вряд ли это проще, чем в случае с прямым портом на C++, но во втором случае мы хотя бы имеем на выходе готовый продукт и полный контроль над тем, как он выглядит.
Во-вторых, наш портируемый код написан не в абстрактном окружении, а вполне конкретном — дотнете. Если где-либо в API торчит System::Collections::Generic::IEnumerable<System::String> — то это значит System::Collections::Generic::IEnumerable<System::String>, а не QList, не std::list<std::string>::iterator, не const char**, и не что-либо ещё из плюсовых концепций. А имнно: этот IEnumerable будет использоваться внутри foreach, в LINQ-выражениях, он будет сохраняться в переменные и возвращаться из функций, конвертироваться в object и извлекаться обратно, проверяться на приводимость к другим интерфейсам и типам, на равенство null, и так далее. То есть, если платформа, на которую мы перетаскиваем свой код, не будет соответствовать какому-либо из этих поведений, код придётся править, и весьма существенно. Аналогично, String должен следовать поведению дотнетовского String, иначе будут проблемы. В этом смысле оторваться от дотнета далеко не так просто, как кажется, особенно при поддержании развивающихся проектов, которые продолжают ежемесячно дорабатываться программистами, работающими в парадигме C#.
Во-первых, всё упирается в объём работы. По сути, нужно портировать (не важно, единовременно или в автоматическом режиме) десятки миллионов строк наших проектов на Haxe для того, чтобы им можно было пользоваться. Вряд ли это проще, чем в случае с прямым портом на C++, но во втором случае мы хотя бы имеем на выходе готовый продукт и полный контроль над тем, как он выглядит.
Во-вторых, наш портируемый код написан не в абстрактном окружении, а вполне конкретном — дотнете. Если где-либо в API торчит System::Collections::Generic::IEnumerable<System::String> — то это значит System::Collections::Generic::IEnumerable<System::String>, а не QList, не std::list<std::string>::iterator, не const char**, и не что-либо ещё из плюсовых концепций. А имнно: этот IEnumerable будет использоваться внутри foreach, в LINQ-выражениях, он будет сохраняться в переменные и возвращаться из функций, конвертироваться в object и извлекаться обратно, проверяться на приводимость к другим интерфейсам и типам, на равенство null, и так далее. То есть, если платформа, на которую мы перетаскиваем свой код, не будет соответствовать какому-либо из этих поведений, код придётся править, и весьма существенно. Аналогично, String должен следовать поведению дотнетовского String, иначе будут проблемы. В этом смысле оторваться от дотнета далеко не так просто, как кажется, особенно при поддержании развивающихся проектов, которые продолжают ежемесячно дорабатываться программистами, работающими в парадигме C#.
0
У меня и в мыслях не было предлагать вам переносить всю кодовую базу на haxe, я прекрасно понимаю безнадежность этой затеи, о чем сразу и написал.
Мне сложно оценить структуру ваших продуктов, их количество и общий размер команды. Я лишь предположил, что у вас могут быть новые продукты или обособленные модули, которые, скажем, можно поставлять в виде .NET dll, C-библиотеки, jar, или просто пакета с исходниками на соответствующем языке.
В этом случае, их можно было бы попробовать писать на haxe и получить некоторые преимущества.
В любом случае, мне казалось, вам должн быть инересен продукт, который решает настолько близкую вашей задачу. Ну я не знаю, хотя бы посмотреть, как дженерики в плюсы выгоняются (флагами компиляции и метой в класск можно делать erasure, можно генерировать типизированную реализацию для каждого инстансированного с новым параметром типа, а можно через мету-же подключить макро-метод, обрабатывающий AST).
Если же вам действительно было интересно, и вы немного посмотрели – то были бы интересны впечатления: может быть вы сделали что-то более удачно, может, наоборот – чем-то вдохновились.
Мне сложно оценить структуру ваших продуктов, их количество и общий размер команды. Я лишь предположил, что у вас могут быть новые продукты или обособленные модули, которые, скажем, можно поставлять в виде .NET dll, C-библиотеки, jar, или просто пакета с исходниками на соответствующем языке.
В этом случае, их можно было бы попробовать писать на haxe и получить некоторые преимущества.
В любом случае, мне казалось, вам должн быть инересен продукт, который решает настолько близкую вашей задачу. Ну я не знаю, хотя бы посмотреть, как дженерики в плюсы выгоняются (флагами компиляции и метой в класск можно делать erasure, можно генерировать типизированную реализацию для каждого инстансированного с новым параметром типа, а можно через мету-же подключить макро-метод, обрабатывающий AST).
Если же вам действительно было интересно, и вы немного посмотрели – то были бы интересны впечатления: может быть вы сделали что-то более удачно, может, наоборот – чем-то вдохновились.
0
А, в этом плане. Нет, обсуждений Haxe у нас не было, по крайней мере, я таких ни разу не заставал. Так что сравнения, к сожалению, провести не смогу. Что касается новых продуктов, то, честно говоря, я не в курсе, как и на чём они пишутся — в компании с десятками проектов и сотнями сотрудников, да ещё и на удалённой работе, многое проходит мимо ушей.
0
Имена файлов по возможности сохраняются (хотя из-за особенностей некоторых сборочных систем для C++ портер старается не допускать присутствия файлов с одинаковыми именами, пусть и в разных каталогах).
Можете рассказать, что за особенности такие, в контексте того что до этого написано что портирование идет на CMake? Или речь не про сборочную систему, а про то что может быть неоднозначность инклюда файла просто по короткому имени, когда не хочется запариваться с порядком инклюдов?
0
Unity build не всегда корректно работает при наличии файлов с одинаковыми именами. Не поручусь, что это так во всех версиях реализации, но какие-то проблемы у нас с этим были.
0
А откуда возьмется unity если вы сами генерите весь cmake? или там таковая поддержка добавляется?
unity объединяет как правило TU в рамках одной shared/static либы. В ее рамках еще куда ни шло поддержать уникальность, но если у вас 200 целей, то это выглядит очень избыточным.
unity объединяет как правило TU в рамках одной shared/static либы. В ее рамках еще куда ни шло поддержать уникальность, но если у вас 200 целей, то это выглядит очень избыточным.
0
RTTI_INFO_IMPL_HASH(1733877629u, ::IFoo, ThisTypeBaseTypesInfo);
Увидел хеши для RTTI нужд, сразу пришла на ум замечательная статья о dynamic_cast за константное время:
www.stroustrup.com/fdc_jcse.pdf
Вы не знакомы с этим методом? Или вам все равно нужно больше чем каст за счет каких-то фич C#, я не знаю даже. Или он не подходит т.к. типа должны кастится за пределами одной шаред библиотеки?
0
В C# возможна проверка на соответствие объекта типу, заданному в рантайме объектом Type или TypeInfo. dynamic_cast требует, чтобы тип был известен в момент компиляции. Чисто теоретически, код, выполняющий каст, можно в виде std::function создать в момент инициализации объекта TypeInfo и потом вызывать для каждого объекта, но мы такого не делали, и я не уверен, что все способы создания объекта TypeInfo предусматривают наличие соответствующего типа в момент компиляции.
За ссылку спасибо — у нас не так давно была внедрена система, позволяющая выполнять касты быстрее, чем нативный dynamic_cast (почему-то его реализация, по крайней мере, под Студией заметно медленнее, чем в C#), надо будет посмотреть, как это соотносится.
За ссылку спасибо — у нас не так давно была внедрена система, позволяющая выполнять касты быстрее, чем нативный dynamic_cast (почему-то его реализация, по крайней мере, под Студией заметно медленнее, чем в C#), надо будет посмотреть, как это соотносится.
+1
T idx_get(int32_t index)
{
return index == 0? m_value: System::Default<T>();
}
Не нашел в тексте статьи про геттеры — cv, в частности const — не поддерживаются для методов? Как-то грустенько видеть неконстантные геттеры.
Понятно что нет аналога в C#, но мб что-то вроде «один оператор return, нет модификации данных = добавить const» бы прокатило.
0
Программисты C# часто используют инициализаторы свойств в составе выражения создания объекта. Соответствующий синтаксис приходится оборачивать в лямбда-функции, поскольку в противном случае записать инициализаторы в составе одного выражения не получается:
Foo(new MyClass() { Property1 = «abc», Property2 = 1, Field1 = 3.14 });
Генерация C++ ограничивается C++11 режимом, не выше?
В уже вышедшем C++20 есть Designated initializers, решающие эту проблему. Это может быть опцией для генератора?
0
Насколько я понимаю, Designated initializers не будут работать, например, с сеттерами свойств. Мы используем стандарт C++14, и ограничены поддержкой VS2017, которая данный синтаксис не понимает. С другой стороны, опцией генератора подобное добавить будет несложно.
0
Последний абзац про аналогию Python и PHP — не смущает слабая типизация в PHP? т.е. одно и то же выражение может проводить операцию над разными типами? Я не говорю что это невозможно, HPHPc, Phalanger, все такое, реализации такого уже были, хоть и ограниченные по подмножеству языка. Такая ли большая уверенность у вас что все прям по тем же рельсам и проблем не будет?
0
В Python тоже слабая типизация и отсутствуют перегрузки методов. Мы генерируем модуль Python, который экспортирует типы, соответствующие типам из нашей сборки. Внутри этого модуля запускается та же самая сборка, а сам модуль отвечает за маршалинг данных и вызовов и сопоставление объектов, а также согласование времени их жизни. Большое количество генерируемого кода как раз и отвечает за разруливание перегрузок в зависимости от фактических параметров вызова. Т. е. конкретно выражения на целевой язык не переносятся (только API), а выражения в пользовательском коде будут следовать обычным для данного языка соглашениям.
Мне представляется, что та же система может работать в других скриптовых языках. С другой стороны, я никогда не занимался написанием модулей для PHP и потому не в курсе возможных подводных камней.
Мне представляется, что та же система может работать в других скриптовых языках. С другой стороны, я никогда не занимался написанием модулей для PHP и потому не в курсе возможных подводных камней.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Трансляция кода с C# на C++: работа портера