Настоящая концпеция является либо близким цитированием, либо творческой переработкой идей Н. Вирта в отношении построения компьютерных систем.
Типичной ситуацией при создании языка программирования является некая идея, которая более точно выражает абстракции реального мира. Реже, но тоже достаточно часто такая идея не выражает идеи конкретного мира, но ориентирована на некии абстракции, которые в конечном итоге отображаются на реально существующие объекты.
Так, например в golang
есть абстракция каналов, которая отражает практическую реализацию обмена сообщениями между облегчёнными процессами внутри программы. С другой стороны, тот же golang
через структуры и привязанные к ним функции отражает абстракции отношений объектов и их поведения. Всё это абстракции реально существующих процессов и объектов для облегчения программирования.
Также есть абстракции другого типа: отражение аппаратных механизмов в понятиях языка. Например, при сложении двух операндов целочисленного типа, у которых размер равен машинному слову -- фактически, это некоторое обёртывание низкоуровневых операций, например:
add eax, rax // Сложить содеримое регистров {eax, rax} и поместить результат в rax
rax += eax // Тоже самое, выраженное средствами языка C-- (условно)
В таких формах явно прослеживается просачивание абстракции машинной операции на уровень языка высокого уровня (впрочем, в указанном примере, C--
на таковой не претендует; но подобные примеры наверняка можно найти во многих языках).
В расширение приведённого примера (по второй его части) при всей схожести операциии сложения на уровне ассемблера и языка высокого уровня -- сложение на языке высокого уровня носит концептуально другое содержание. Операндами оператора +
являются символы оснащённые семантикой, которой нет на уровне ассемблера. При всём том, что базовый тип операндов всё ещё является int
-- на высоком уровне операнды могут обладать семантикой типа метр
, яблоко
, кг
. И таким образом, не смотря на весьма похожую форму концептуально высокоуровневая операция сложения не может быть адекватно отражена на уровень ассемблера без потери сути.
Форма одна, суть разная.
Такая протечка высокоуровневых абстракций в языках высокого уровня имеет под собой вполне определённую причину: язык был сконструирован, как производный продукт от процессора. Это и называется первородный грех языка. И хорошо, если язык был сконструирован. Очень часто язык сочинён.
Семантический разрыв между средствами языка и возможностями аппаратуры порождает некоторое пространство, которое условно называется подвал. Подвал, как и любое помещение с затруднённым доступом -- не является пустым. Там присутствуют различные существа, смутные тени которых и пугающие звуки создаваемые ими -- пугают нас. Мы не любим спускаться в подвалы, наводить там порядок и ещё хуже -- оставаться в одиночку в темноте.
Эта метафора точно отражает состояние семантического разрыва между аппаратными возможностями и возможностями высокоуровневого языка программирования, который подвержен первородному греху языка.
Подвал населяют сущности, которые заполняют собой такой семантический разрыв. В подавляющем большинстве случаев житель подвала -- аппаратно-зависимый ассемблер. Кроме него там же могут проживать различные аппаратные особенности конкретной аппаратуры, которые могут не входить в семантику языка и с высокой вероятностью также непереносимы между аппаратными платформами.
Кроме того, выход на уровень ассемблера отсекает почти все абстракции языка высокого уровня оставляя программиста с химерами желаемых возможностей в вакууме беспомощности. Почти нет типов, нет структур, нет контроля за состоянием, нет линтеров, нет проверок на выходы за пределы структур. Память не имеет встроенной проверки на выход за границы (не считая аппаратных возможностей, но их срабатывание как правило фатально).
На том этаже, на котором находится язык высокого уровня есть встроенные меахнизмы, которые направлены на облегчение труда программистов. Это различный синтаксический сахар, различные правила видимости, владения, мутабельности и т.п. И чем больше таких возможностей -- тем больше скрытая часть языка, которая постоянно наблюдает за программистом. Эта скрытая часть и есть шкаф со скелетами. И чем больше язык предоставляет таких возможностей -- тем больше этот шкаф. И тем больше в нём скелетов.
Это порождает проблему реализации компилятора такого языка. Первая реализация (очевидно) будет сделана. Она с высокой вероятностью будет содержать ошибки, какие-то странные компромиссы, пыльный омертвевший код и никому ненужные возможности. В какой-то момент всё это приведёт к тому, что шкаф займёт всё помещение, что занимает язык высокого уровня. И помещение превратится в склеп с мертвецами.
Чтобы максимально сузить разрыв (устранить подвал) -- язык высокого уровня должен максимально точно отражать свои абстракции на аппаратуру. В идеале -- не должно быть даже мельчайшей щели для ассемблера. Как показывает опыт из разных сфер: 20% усилий даёт 80% результата. Можно достигать и большей степени соответствия, но оставшиеся 20% потребуют 80% усилий, что будет экономически нецелесообразно. Но для каких-то особых применений, наверное, потребуется и такое соответствие.
Общий вывод по разделу: язык должен быть максимально простым и программирующим логику аппаратуры. Простота нужна, чтобы не испытывать сложности в проектировании аппаратуры. При этом язык не должен скатываться до примитивного уровня, в противном случае -- это будет ассемблер в другой форме.
Хватит разводить пауков шкафу и прятать в нём скелеты. Язык не должен развращать программиста вкусовыми добавками. Язык программирования в зависимости от его объема может выступать как яд, а может как лекарство -- всё зависит от дозы. Очевидно, что отсутствие всяких дополнительных возможностей языка сделает его крайне неудобным с практической точки зрения. Слишком большой шкаф -- будет выкручивать руки программисту и постоянно ему отдавливать пальцы своим весом. Поэтому, тут тоже следует пользоваться правилом: 20% усилий дают 80% результата. Какие-то вещи должны остаться в шкафу, чтобы не захламлять пространство языка. Но при этом он не должен превращаться в недвижимое имущество. Иначе язык будет неспособен к портированию на другие платформы.
Идеальные размер шкафа -- небольшой саквояж. В таком виде там врядли поместится хотя бы один скелет.
Точно также, возможны особые случаи: когда от шкафа необходимо избавиться совсем. Если такая необходимость действительно возникнет -- именно так и следует поступить, не забывая о том, сколько это будет стоить.
Язык следует считать системным при выполнении ряда условий. Часто приходится слышать в корне ошибочное обывательское мнение о свойствах такого языка.
Один из таких мифов: язык должен позволять работать с сырой памятью машины, чтобы считаться системным. Нет, такое архитектурное решение приведёт к тому, что такой язык будет опасным.
Другой миф гласит: если у языка нет ассемблера -- значит это прикладной язык. Существует достаточное число примеров, когда сначала был разработан язык, а потом был разработан процессор. Т.е. прослойка в виде ассемблера была сведена к минимуму. Такие примеры есть и у Интел, и у АРМ, и у СССР, и у Японии.
Ещё один такой миф гласит: в языке есть рантайм, поэтому это не системный язык. Наличие рантайма на самом деле никак не влияет на свойства системности языка. Существует масса примеров, когда рантайм не называется рантаймом, но по факту таковым является на все 100%. Например, ОС является рантаймом процесса. С той лишь разницей, что ОС и процесс как правило разделяет огромный семантический разрыв. Или, например, драйвер и процесс. Фактически, драйвер -- это рантайм потоков ввода-вывода по отношению к процессу, но их точно также разделяет семантический разрыв. И везде, где встречается семантический разрыв -- это отличное место для разведения различных паразитов.
Таким образом системный язык должен отвечать следующим требованиям:
Любое инженерное решение в нашем реальном мире -- это компромисс между двумя крайними точками:
Истина находится где-то по середение.
Существующий мейнстрим ИТ давно идёт широкими шагами в пропасть. Безопасность, переносимость, управляемость ПО -- стоят крайне дорого. Бизнес не желает тратить свои ресурсы на эти вопросы. Бизнес желает приватизировать доходы и национализировать расходы. Бизнес покупает то, что ему продают. Увы, то что рекламируют не является тем, что стоит бизнесу покупать.
Это не означает, что теперь нужно расслабиться и получать от жизни удовольствие. Любая рыба, которая желает плавать в чистой воде -- должна плыть против течения. Другого пути нет. Путь указан, цели поставлены -- за работу, товарищи!
2023-08-02, SVI.