Немного рассуждений о языках программирования (ЯП) с уклоном на надежное и безопасное программирование.
Статья не публиковалась ранее, хотя была написана в 2019г, теперь можно смотреть как некую ретроспективу. Чем и воспользуюсь, вставляя замечания о былом по тексту (тег Upd).
Но тормозит развитие серии, ибо вышли уже 3 части и несколько переводов в тему:
часть 1. Надежное программирование в разрезе языков — нубообзор
часть 2. Надежное программирование в разрезе языков — претенденты
часть 4.0 - в заморозке - посвящена подробностям о косяках в Rust, сейчас смысла оживлять её нет – время уже всё показало
часть 4.1 - в заморозке - посвящена подробностям о D, может будет, а может и нет - но на общую канву серии не влияет
часть 5. И мышонок, и лягушка. Универсальный Компилятор – не была объявлена в заголовке частью серии, планировалась исключительно ради Swift, но немного разрослась в сторону
часть 6 планируется посвятить выросшим и стабилизировавшимся языкам новых поколений, пригодным к использованию, но и с некоторым оттенком некромании
часть 7 планируется про бастардов С++
Специально написана в провокационном стиле, в этом часть идеи - так что резко реагировать не стоит.
Не теоретическое, но ближе к практическому применению.
После долгого самокопания и размышлений, см.первые части и статью Александреску “Какой язык — D, Go или Rust имеет лучшие перспективы заменить C и почему”, подвожу итоги.
Упс, хорошо что я Александреску прочитал позже чем написал свое мнение. Оно другое - я далеко не настолько умный для 200% метапрограммирования.
В процессе уточнились в лучшую сторону характеристики (параметры) надежности некоторых языков в сводной таблице к первым частям, и также добавилась пара участников.
Попытка найти общее решение увенчалась полным провалом - универсального подхода, получить и системный и прикладной и надежный и продуктивный язык - нет совсем.
Потому финал получается подчеркивая сильные области и отдельное мнение сугубо для себя, поскольку у всех разный рабочий бэкграунд и опыт.
Таблица с областями возможного применения ЯП заменена на теги, надеюсь достаточно самообясняющие: gamedev, web, desktop, enterprise (db+web OR +desktop GUI), math, CLI, mobile, embedded (bios, kernel), system, HFT
Итак среди рассмотренных:
Active Oberon
desktop, embedded, system
Проблема начинается в фактически отсутствующем компиляторе - его нужно выковыривать из цепких объятий АОС A2 (операционная система) и дорабатывать. Далее, нужно дописать себе ГУИ, Веб, СУБД….Задача для большого коллектива, а комьюнити почти нет.
Кроме того, дженериков и обработки ошибок нет, продуктивность написания низкая.
Оно того не стоит - хотите [современной] простоты - смотрите на Go - он легко воспринимается после Оберона, имеет схожую модель объектов, лучшую обработку ошибок, хотя дженериков тоже (пока) нет.
Upd. Дженерики в Go появились, осталось поныть только про бойлеплейты обработки ошибок. Но с точки зрения надежности это всего лишь мелкое замечание - возможно внесение ошибок, забыв что то поменять после копипасте.
Upd2. Из этого семейства ЯП в GCC 13 включили стандартную Modula-2. Но это очень простой язык без современных возможностей.
Upd3. Если покопать в Интернете, то можно найти компиляторы в исходных текстах и Modula-3 и нескольких ревизий обычного Oberon'a (интересен, например Eberon). К практическому применению, тем не менее, это вряд ли приведет.
Ada
web, desktop, enterprise, embedded
Наверное наилучшие показатели в плане проработанности и надежности.
Возможны проблемы с библиотеками, есть отзывы по сложной интегрируемости Ады со сторонними. Тяжелый многословный синтаксис. Коммерческий компилятор дорогой, но есть GNAT Ada.
Для меня просто слишком много надо переучиваться без заметной выгоды. Но для небольшого коллектива уже стоит думать, особенно для специальных задач, где не требуется широкий набор фреймворков - может для исследовательских институтов?
Не особо обновляется поддержка Android, iOS нет совсем, для Web тем не менее живет Ada Web Application, A W S - Ada Web Server и Ada Server Faces
Upd. Внезапно, совпало с сегодняшней новостью - Ada в Tiobe 9. Июльский рейтинг TIOBE: Ada обогнал SQL, Perl и Fortran и занял 9-е место
BetterC и D
gamedev, web, desktop, enterprise, math, CLI, mobile, embedded, system, HFT
Изначально рассматривался как один из самых перспективных вариантов.
Но в итоге средний по надежности и есть глобальные проблемы. Из упомянутых Александреску, более-менее успешно решается только проблема сообщества - сейчас №21 в индексе Tiobe (Upd съехал до №44). Хотя у меня отличный от взгляд на вещи.
Первая - это проблема выбор компилятора, см. также п.4 ниже. Есть референсный DMD, но с ограничениями по платформе и средним оптимизатором, на данный момент версии 2.087.1 (upd 2.111); далее есть GDC на базе GCC поддерживающий 2.081.2 и для которого есть bare metal пример, но его развитие сместилось в область полной интеграции в большой GCC, ценой чего явился откат на стабильную версию фронтенда языка (FE) 2.076, режим BetterC включается через -fno-druntime и пока не вышедший например для Win; и наконец есть LDC на базе LLVM с поддержкой Android (и бета поддержкой iOS), немного отстающий от референса - сейчас FE2.0.86.1 (это примерно 1.5 месяца). Upd. В стабильной версии GCC, начиная с 9.2
BetterC практически неприменим для больших задач - надо начинать писать свою стандартную библиотеку - есть только libc и некоторые возможности вроде Nullable!. Но отлично выглядит для портирования старых С-программ, особенно CLI, что добавит 80% надежности и можно рассмотреть для микромашинок - хотя bare metal и не поддерживается официально. LDC поддерживает ARM и BetterC режим.
D из-за Garbage Collector (GC) теряет целый класс задач - см презентацию со скоростными характеристиками с DConf 2019 https://youtu.be/TkNep5zHWNw?t=309 - до 330мс паузы на 1.5Гбпамяти при активном использовании ГЦ (95мс экспериментальный ГЦ), но в прикладной области выглядит прилично. Есть целое руководство, как бороться с GC, но не так то это просто https://dlang.org/blog/the-gc-series/
D из-за высокой завязки на метапрограммирование и плавающего даже между минорными версиями синтаксиса (2.080 и 2.085) с имеет очень слабую “преемственность”. Приложение перестает собираться и еще хрен разберешь почему - шаблоны очень сложно диагностируются. Впрочем, включение в GCC9, стабилизирует этот эффект. P.S да не так то уж всё и плохо - см. Rust =)
Для систем повышенной надежности нужно сделать свою SafeStd библиотеку, гибкость языка позволяет сделать типы SafeInt с контролем переполнения (есть core.checkedint), да и последняя инициатива скопировать ОВ-модель (Ownership & Borrow) безопасности памяти у Rust, см перевод статьи Заимствование заимствования может дать положительный эффект.
Поддержка Андроид появляется в LDC и уже в GCC 9(видео с DConf 2019 https://youtu.be/TkNep5zHWNw?t=1689 ), iOS даже не ближайшая перспектива.
Из IDE выбор небольшой, особенно с возможностью отладки, - плагин для Visual Studio Visual D , минималистическая Dlang IDE (написана чисто на D, собрать ее небольшой квест из-за п.4), чуть менее минималистичный Code::Blocks, и еще плагины неизвестного качества для Intellij, VS Code и Atom.
Upd. За прошедшее время произошел еще один раскол сообщества - сторонники пуристы OpenD The Open D Programming Language, топящие за GC но с максимумом функционала против сбалансированного но фрагментирующего подхода создателя языка с поддержкой noGC в том числе. Напомню, первый раскол был с переходом D1 -> D2.0 с полной переделкой стандартной библиотеки.
IEC 61131-3 ST
embedded
Живет себе в контроллерах и живет. Слабых мест по надежности мало - математические переполнения и синхронизация задач. К слову сказать - по надежности работы с памятью обгоняет даже Rust - динамической памяти считай что нет, указатели константные с контролем размера деста при копированиях.
Слабая продуктивность для общих задач - нет генериков, нет библиотек общего назначения.
Собственно я там в ПЛК и его использую. Но чтобы расширить применение на десктопно-серверный класс задач, нужно делать биндинги или создавать все фрймворки с нуля. Вряд ли кто за это возьмется - полно конкурентов с готовыми наработками.
Safe-C
Скорее любительский проект. Нет документации, сообщества, только x86 компиляция, минимальный набор библиотек.
Upd. Затронем тему подробнее в части 7
Rust
gamedev, web, desktop, enterprise, CLI, embedded, system, HFT
Много достоинств с точки зрения надежности и вполне положительный ранкинг в таблице, растущее сообщество. Пристально присмотрелся к отзывам, пришлось даже прочитать учебник RbE =)
Собственно, к надежности претензия одна - синтаксис сбивает человека, читать чужой код тяжело - тяга к минимизации исходного кода (синтаксис с массой спецсимволов и особенно лямбды и возвраты данных самыми неожиданными способами) дает свой черный вклад. Кроме того, сложность квадратично умножается количеством реализованных синтаксических сущностей - здесь есть атрибуты, трейты, методы имплементации (ООП), это все может быть шаблонизировано и анонимизировано (замыкания и лябды) с автовыводом типов, ну и на сдачу - AST-макросы(с отдельным синтаксисом o_O). Дополнительно к ручному управлению памятью здесь возможно ручное указание времени жизни, причем время жизни полей структур можно указать отдельно от времени жизни объекта. У компилятора же проблем с написанием и чтением программы нет, и если вы сможете Это скомпилировать - оно работать будет, и кстати будет быстро и со скромным использованием памяти. Прекрасно!
В качестве IDE есть плагин для CLion от JetBrains. https://plugins.jetbrains.com/plugin/8182-rust и плагин для IntelliJ https://intellij-rust.github.io, еще есть неофициальный Rust support for Visual Studio Code https://marketplace.visualstudio.com/items?itemName=rust-lang.rust
Upd. JetBrains выпустила специализированную среду RustRover, а плагины для MS IDE стали rust-analyzer.
Дополнительно всплывшие неприятности.
Я выше ругался на D на то что минорные изменения ломают код. Здесь ситуация в разы хуже из-за сырости языка и более жесткого подхода к попытке контролировать что нужно и что не нужно. Ходить недалеко - смотрим статью https://habr.com/ru/post/458848/ месячной давности и вдумываемся - стабилизировали alloc! (это простите основы), переписали стандартную библиотеку std кусками, поменяли логику контроллера ссылок NLL (я умудрился в учебнике наступить на пример, как в статье) сломав 220 сторонних библиотек, которые как зависимости утащили за собой еще 2000.
Библиотек реально мало, например в сравнении с Go. И мало того, из-за пункта выше, их будет становиться меньше - кто же будет постоянно чинить то, что сломал не сам.
Пример разработчика Way-Cooler - оконного менеджера для Wayland как человека, сломавшегося бороться с мельницами (и откатившемуся на C) http://way-cooler.org/blog/2019/04/29/rewriting-way-cooler-in-c.html там же пример, во что превращается растовый код при серьезном применении https://github.com/swaywm/wlroots-rs/blob/91a18bd541a6ec565d6ef78d18ee5cc6a413f684/src/macros.rs#L201 . И не стоит тут вспоминать про фортран - сложность фортрана и такого кода - это как сравнивать школьные задачи на линии и геометрическую топологию.
Самый медленный в мире компилятор. Да и Cargo не блещет - из-за языка приходится дробить на мелкие крейты, что скорости сборке не добавляет.
И лично для меня стопперы
Я не орел, и работаю не в курятнике - потому в птичий язык не умею, Но наверняка есть лучше адаптирующиеся люди.
Странное и нелогичное поведение компилятора, местами противоречащее описанию примеров, начинается еще в учебнике.
Слишком много барьеров при написании - продуктивность будет околонулевая. Лично мне компилятор, который будет мешать работать - не нужен. И это даже касается не только системы заимствования - достаточно других проблем с типами.
Нужных мне библиотек нет.
Собственно, неготовность к эксплуатации для меня очевидна - слишком ржавый от сырости. А проблемы других языков кажутся презрительно мелкими после такого.
Upd. Потихоньку стабилизируется, очень потихоньку прирастает библиотеками, весьма модный - Tiobe #19, но краеугольные проблемы никуда не ушли.
Upd2. К примеру - на данный момент даже нет визуального редактора, написанного на Rust - Helix - это vim-порно, а Zed не кроссплатформа с массой проблем. Собственно, я недолго думая, прикрутил компилятор к Code::Blocks.
Планировалась статья часть 4.0, где собраны все недоработки, но не стал публиковать, потерял интерес к языку, тем более список выявленных проблем регулярно обновляется практикой. Только очередной срач разводить на ровном месте.
Go
gamedev, web, desktop, enterprise, CLI, embedded, mobile, HFT
Новый претендент. Весьма простой, возможно даже слишком - мало синтаксического сахара, обероноподобный синтаксис и примитивная объектная система, контроль указателей, GC, основы ФП. Виртуальных функций нет, потому реализация сложных типонезависимых структур только через интроспекцию, что скажется на скорости (однако она выглядит достаточно неплохой). Upd. Скорость стала даже очень неплохой, сравнима с лидерами.
Стоит отметить неплохой выбор прикладных библиотек. И отдельно Go Visual Studio Code и GoLand от JetBrains .
Его критикуют за отсутствие дженериков, которые возможно введут в 2.0 и за простую обработку ошибок - впрочем, вполне достаточную. Upd. Ввели
С точки зрения надежности есть некоторые нюансы с приведением nil в ADT https://go.dev/doc/faq#nil_error, полностью отсутствует контроль при вычислениях, как целочисленных, так и с плавающей точкой, и можно напортачить в многопоточных приложениях. Еще прогнозируется такая проблема, что отсутствие дженериков приведет к переносу части логики на нетипизированный interface{} с последующими ошибками контроля типов в рантайм.
Embedded - это нестандартное применение и осложнено великоватым размером бинарников, но примеры тут Golang Powered Robotics, TinyGo - Go compiler for small places - для Raspberry - подобных без проблем, но если ресурсов меньше, то уже надо смотреть на Go в лупу.
Далее, Go позиционируется как серверный язык, и потому применение для десктопа не предусматривалось создателями, но тем не менее есть привязки к Qt, GTK и куча минисерверных вариантов по типу Электрона (но есть и покомпактнее) Awesome Go GUI .
Есть какая то минимальная поддержка для мобильных устройств Android и iOS Go Wiki: Mobile .
C# (вне конкурса)
gamedev, web, desktop, enterprise, math, CLI, mobile, embedded, HFT
Собственно, вроде и хороший язык и всё при нём, но по моему развитие пошло куда то не туда. Решая часть проблем, добавляет новых. Буду использовать через заставь себя - тяп ляп и готово.
Я уже отсеивал его из-за интерпретатора для ембеддед, .NET Micro Framework заброшен с 2015г, хотя получил развитие как TinyCLR OS
Upd. Жизнь C# в этом направлении .NET nanoFramework – Making it easy to write C# code for embedded systems еще теплится, но популярности не обрела.
Хорошие показатели надежности, но проблемы с (1)GC, и плохо лезет в ПЛК, лаги заметны на глаз (2), плохая кроссплатформа GUI (3) - сложная WPF, и нетривиальный ни на что не похожий ASP.NET.
Upd. Развели полный бардак в плане кроссплатформенного GUI, сам черт ногу сломит - только официальных 8шт. Overview of framework options - Windows apps | Microsoft Learn
Проблемой надежности для меня является …. декомпиляция исходного кода (4) и никакая защита.
Проблемы (2),(4) решит ли NET native?
NET Native is 41.6±0.8 % faster than .NET JIT
Upd. NET Native долго росло от обещаний к возможности его использовать, но результат в .NET 9.0 околонулевой, более того, получили еще и гигантские бинарники под 100Мб.
Надежность? Часто наблюдаются выпадающие приложения по RT exceptions. Развели, понимаешь … инклюзивность и разнообразие.
Частые ошибки при программировании на C#
Учебник checked-unchecked-overflow
Upd. Добавилась неприятная особенность в мильоне разных версий языка (какая там уже - 14я?), которые прибиты к версиям NET и Студии и мешают переносимости.
Итого, финалист (для меня) C++14/17/…
Огромное комьюнити, библиотеки, перспективы, я его терпимо знаю, компиляторы есть везде.
Да, старые известные проблемы с датарейсингом, мемори сэфети и диким синтаксисом шаблонов с кучей УБ-камней, самые медленные компиляторы (медленнее только Rust).
Потому выбор ЯП получается не окончательный, а выбор из-того что есть. Костылями придется затыкать дырки в надежности:
строго С++11 и выше написание - только STL, никаких raw-массивов, строк и указателей
следование правилам программирования MISRA, аэро, гугла итп
линтеры помогут доглядеть ловушки (и спасут=)
арифметическое переполнение решается написанием/использованием библиотеки пользовательских классов
модульность….ну когда-нибудь в 2022
контрактное программирование - тогда же
….
Upd. Многое допилили, прогресс идет. В детали углубляться тут не буду.
Полуфиналисты
для маленьких систем D
для коллективов Ada
для маргиналов Rust
Upd. Есть еще нишевые языки, очень хорошо себя показывающие в определенных областях, возможно в части 6.
Заключение, но не конец
Честно говоря, мне немного жаль, что нельзя например, написать ядро системы на Rust, сетевую подсистему на Go, а юзерланд на D.
Откуда у меня все такие проблемы. Просто выяснилось в разных проектах, что написание на C тянет очень много отладки, а переписывание старой системы с C++Builder на C# хоть и решает проблемы с утечками итп, но практически программа получается в разы (и это еще оптимистичная оценка) тормознее. Кроме того, возникает слаборешаемая проблема декомпиляции, что вкупе с платформозависимостью ставит кресты на универсальности решетки.
13-11-2019
Upd. А за прошедшее с 2019 время все планы пошли прахом. Пришлось много поработать с IEC ST, C#, и даже вспомнить Delphi. А никак не с тем, чем хотелось бы.
includedlibrary
Тема на самом деле интересная. Я прочитал все 3 статьи из цикла, и у меня сложилось впечатление, что языка, который обеспечивает надёжность нет. Языки из обзора либо слишком непопулярны (D, Ada), либо уже заброшены, либо C++ :) Но я для себя давно пришёл к выводу, что на любом языке можно писать надёжный код, если соблюдать дисциплину и наоборот. Например, недавно была новость про переписывание tmux на rust с 67к си кода на 87к строк unsafe rust кода, что определённо менее надёжно, чем tmux на си, который уже обкатан. Есть ещё языки с завтипами, например, agda, idris и т.д, но даже там никто не застрахован от ошибок, потому что так или иначе дело дойдёт до ввода вывода