Введение
С 70-х годов развивается Simplified English, цель которого — определение подмножества языка, понятного широкому кругу неносителей языка. Рекомендуется, например, для технической документации. Автоматические переводчики на таком подмножестве будут работать заведомо корректнее, в идеале генерируя текст, не требующий ручной корректуры.
Если применить этот подход к C# для задачи автоматической конвертации кода в другие языки программирования, то можно выделить подмножество конструкций языка, системных библиотек и технологий, которые потенциально могут транслироваться в широкий круг других языков. Причём конвертации не однократной (миграция), а постоянной для расширения интеграционных возможностей проекта на C# — чтобы в любой момент можно было получить рабочий код на другом языке без необходимости какой-либо его правки.
Позвольте представить: UniSharping
Ограничение C#.NET для решения этой задачи мы назвали U# (Universal Sharp), а процесс конвертации и его инструмент — UniSharping. Исполняемые модули, настройки и документация выложены на GitHub, система бесплатна для некоммерческого использования (Non-Commercial Freeware).
В целях кроссплатформенности Компания Microsoft уже сделала ограничение .NET Framework в плане библиотек и технологий: .NET Core. Это как бы первый шаг в нужном направлении, U# делает второй шаг к «кросспрограммируемости».
Ограничений U# в конструкциях языка оказалось немного – это атавизмы goto и case goto, а также yield, не моделируемый адекватно в автоматическом режиме. Не рекомендуется (хотя и можно) использовать struct, есть нюансы с наименованиями – всё это подробно описывается в отдельном документе. Парсер U# выдаёт ошибки и предупреждения, и для гарантии корректной генерации следует так подкорректировать исходный код C#, чтобы они в идеале совсем исчезли. Если всё-таки нужно сохранить исходный вариант, то можно использовать директивы препроцессора #if JAVA || PHP … #else … #endif. Данные ограничения действуют на уровне движка U# и не подлежат коррекции извне, как и список поддерживаемых языков.
А вот ограничения на уровне системных библиотек заданы не жёстко и конфигурируются извне через специальные текстовые файлы, определяющие, как переводить на соответствующий язык тот или иной класс и его члены. Если есть прямой аналог, то он и указывается, если ситуация сложнее, то пишется или фрагмент кода конечного языка, или вообще специальный (сервисный) класс, решающий нужную задачу. В совсем уж сложных случаях приходится «хардкодить» на уровне движка, но такие ситуации довольно редки (с десяток). Порядок настройки на системные классы и их члены описываются в отдельном документе. Вот список поддержанных классов C# и их членов с аналогами на Java и Python в текущей версии на сайте, там же есть online-демо.
Что касается технологий, то сейчас список ограничен консольным приложением и юнит-тестами (UnitTest). Ну и отдельные Lib-проекты, как частный случай, переводятся в соответствующие конструкции нужного языка.
Для успешного перевода исходный проект C# (solution) должен иметь некоторую запускаемую часть, проверяющую работоспособность в рамках исходного C#. Хорошо, если это обширная система авто-тестов (стандартных UnitTest в разных реализациях или самописных), но по минимуму должно быть хотя бы консольное приложение, которое при запуске без какого-либо пользовательского вмешательства отрабатывает правильно. Необходимость этого очевидна – после генерации на конечный язык можно сразу проверить работоспособность. В идеале все тесты должны работать аналогично C#.
История проекта
Идея такого конвертера витала давно. Мой основной проект SDK Pullenti по обработке естественного языка — идеальный кандидат для конвертации: большой объём сложного и постоянно совершенствуемого кода. Для интеграции с Java приходилось оборачивать в web-сервисы, tcp-сервера и пр.
Летом прошлого года нашлось время и силы для создания первого варианта. Он переводил проект Pullenti на Java, а также сам себя на Java.
Следующие полгода конвертер развивался на нескольких внутренних проектах, которые были в компании, в основном посредством расширения системных классов.
Весной 2018 появилась мысль поддержать и Python, что и было реализовано к лету. Но включение второго языка не было предусмотрено в начальной версии и получилось коряво. Пришлось летом полностью переделать движок для потенциальной возможности нескольких конечных языков. Также настройки на системные классы из хардкода были вынесены во внешние текстовые файлы. Надеюсь, это множество будет расширяться не без вашей помощи.
Дальнейшие планы пока таковы:
- подтянуть Python до уровня Java. Сейчас Python поддержан на уровне Pullenti, однако Java по сравнению с ним ушёл далеко вперёд на других проектах.
- поддержать PHP хотя бы на уровне проекта Pullenti.
- поддержать С++. Да, осознаю, это очень сложно, так как неясно при освобождении памяти — какой указатель является ссылкой, а для какого нужно делать delete. Но есть идеи...
Кому это может пригодиться
В основном тем, кто разрабатывает потенциально кроссплатформенные SDK на C#. Благодаря конвертеру UniSharping их SDK может стать ещё и "кросспрограммным", что расширит круг потенциальных пользователей.
В последнее время в России усилились позиции СПО, которые стали обязательными в большинстве государственных структур и некоторых крупных компаниях. Объяснить, что .NET Core тоже СПО не всегда получится, потому что "Microsoft". Пусть некоторая компания разрабатывает свою информационную систему на C#. Чтобы внедрить продукт в "СПО-компанию", можно выделить логическую часть проекта (back-end), её автоматически конвертировать в релизы по мере необходимости, а визуальную часть (front-end) делать на СПО. То есть продолжать разработку на C#, а на Java только front-end.
Я не исключаю, что в принципе возможна конвертация и web-проектов (с ограничениями, естественно), но у меня нет для этого нужных навыков и информации. Если кто видит такую возможность, то её вполне можно реализовать в UniSharping.
Отмечу, для для реального сложного проекта C# поддержка Java или другого языка потребует некоторых усилий по модификации кода, выделении в проекте портируемой части, "обкладывание" её юнит-тестами. Также настройка ещё неподдержанных системных классов и методов и исправление ошибок самого UniSharping (с моей помощью) — работа ещё та. Но процесс сходящийся, в конце которого проект ожидает бонус "кросс-программности".