Интерпретатор языка MSH
Предлагаю вашему вниманию свое видение идеального языка. В предыдущих своих статьях я уже излагал свое представление об идеальном языке От MUMPS к MSH Особенности и отличия языка программирования MSH от MUMPS.
Отзывы были в основном негативные. После их прочтения отзывов я с удивлением обнаружил, что в мире языков программирования все уже очень идеально. Но меня грызут смутные подозрения, что все не так хорошо в этом мире. Языков конечно уже очень много, но многообразия концепций языков не наблюдается.
Если отбросить мелкие украшательства языков, то таких концепций несколько.
- Объектное программирование.
- Управление данными, типизация.
- Передача переменного числа параметров в процедуры и функции.
- Управление процессом выполнения.
Из решения этих проблем и складываются свойства того или иного языка программирования.
Объектное программирование
По моему это важная концепция и она обязательно должна присутствовать в языке. Конечно даже если в языке нет классов и объектов, то ни что не мешает мыслить и писать программы в объектном стиле, но все таки наличие таких механизмов позволяет упростить эту задачу.
Управление данными, типизация
Я считаю этот раздел самым важным в концепции языка. Я встречал много обсуждений на эту тему на Хабре. В основном спорили сторонники статической и динамической типизации. У динамической типизации преимуществом называлось гибкость языка, но недостатком якобы является ненадежность языка и плохая адаптируемость к средам разработки. У статической типизации все с точностью до наоборот. Я считаю доводы о лучшей надежности языков со статической типизацией абсурдными, возможно что статическая типизация помогает в разработке средств программирования, но не более того. Я не являюсь сторонником ни того, ни другого подхода. Я считаю типизацию как таковую основным злом современных языков программирования. Хотя она присутствует в абсолютном большинстве языков программирования. Язык должен полностью брать на себя все управление данными, в том числе разбираться с их типами. Что вполне реально. А программист должен заниматься логикой программы. Если надо проверять данные, то типизация в этом ничем не поможет. Их надо просто проверять на содержание. Наличие типизация я могу объяснить только традицией и косностью мышления.
Передача переменного числа параметров в процедуры и функции
Это мелкая проблема, но она с трудом решается большинством языков. Хотя прекрасный пример существует в Ассемблере. Передача параметров через стек. Надо просто отказаться от списка формальных параметров, а передавать параметры через какой либо список. Возвращать переменное число значений функции мне не совсем понятно для чего и как этим можно воспользоваться. Возвращать в любом случае надо какую то одну сущность.
Управление процессом выполнения
Этот раздел я то же считаю определяющим для концепции языка. Управляющие конструкции языков почти одинаковы. Небольшие нюансы возникают с использованием команды goto. Мне не понятно почему с таким остервенением борются с этой командой. Очень удобная команда, особенно если аргумент этой команды можно вычислять. В реализации параллельных вычислений вариантов варианта в основном 2. Либо они реализуются средствами библиотек, либо могут быть включены в сам язык. Я сторонник второго способа.
В языках отсутствует обработка событий. Хотя она широко применяется. Для построения GUI, для реализации обработки событий запускается главный цикл. Такое решение не блещет элегантностью. Залезть внутрь такого цикла еще та проблема. Нормальный язык должен иметь средства обработки событий.
Мои представления конечно субъективны, и возможно даже неверны. Но они основаны на моем личном опыте. Современная ОС это куча не отлаженного хлама, который не будет отлажен никогда. Нагромождение API, различных библиотек из которых сыпятся ошибки. Количество языков программирования превысило все возможные пределы. Причем принципиально они мало отличаются друг от друга. А о количестве фреймворков вообще промолчу. Любая даже средняя система это многослойный пирог из различных, возможно плохо совместимых подсистем, полная отладка которых не будет выполнена никогда. Отладка простейшей программы на Си может занять месяца. И все это по моему мнению порождено типизацией в языках программирования.
На данный момент языка отвечающего моим представлениям о правильном языке программирования нет. Наиболее близок к нему по моему язык программирования MUMPS, но реализации такого языка как языка программирования не существует. Есть реализации баз данных в которых в качестве языка используется этот язык. Ограниченность такого подхода очевидна, что и заставило меня разработать новый язык MSH и написать его реализацию в виде интерпретатора. На данный момент в нем реализовано не все то что я собираюсь сделать. В частности нет среды разработки, но представление о языке получить можно.
Реализация выполнена для ОС Linux x64.
Кого заинтересовала моя работа пишите на почту, вышлю дистрибутив.
PS.
MSH не только безтиповой язык, он бездекларативный. В нем в принципе нет никаких описаний переменных. В общем случае переменная имеет не только тип, но и структуру. Массивы, списки, HASH, стеки и для описания каждой из структур требуется декларация. В MUMPS подобных языках деклараций нет в принципе, любая переменная является деревом. Никакое место под такое дерево не резервируется. Узел дерева создается в момент записи в него данных и только такие узлы существуют, в которые производилась запись. Ограничения на тип индекса отсутствуют. Поэтому сравнение MUMPS с PHP, Java Script и другими языками некорректно. MUMPS это отдельный мир, со своими проблемами и достоинствами. Чтобы его понять надо перестроить мышление. Понять MUMPS прочитав ругательные отзывы невозможно. Надо погрузиться в него. Прочитать документацию. Установить MUMPS систему. Поработать на нем. То что здесь меня не понимают это вполне закономерно. Мы говорим о разных мирах. В мире MUMPS не бывает обсуждений которые мы здесь ведем, о типах, структурах. Мало кого из MUMPSистов интересует как вообще и где хранятся их данные. Любые данные в MUMPS всегда имеют два представления это число и строка. И в зависимости от операции берется то или иное представление. Я всегда точно знаю результат в зависимости от операции которую я применил. MUMPS заставляет программиста работать в терминах дерева. Деревья могут находиться как на внешних носителях: глобали(аналог баз данных), так и в памяти: локали (аналог переменных в программах). В основном при проектировании информационной системы, я напрямую работаю с данными на диске промежуточных локальных данных у меня минимум и они не создают мне каких бы то ни было проблем. Поэтому на MUMPS форумах вы не встретите обсуждений о типах переменных их локализаций. Типичный способ проектирования это проектируешь входные деревья, выходные. А затем по мере необходимости пишешь программы по формированию входных и выходных деревьев. Данные в MUMPS первичны, а программы вторичны. Своими статьями я преследую цель познакомить как можно больший круг программистов с этим другим миром MUMPS. Я считаю этот мир более правильным. Я восхищаюсь эти простым, мощным и элегантным языком. Мне доставляет наслаждение писать на нем. К моему глубокому сожалению мне мало приходится это делать. Я хочу создать язык на котором можно будет все написать, не выходя за пределы этого языка. Написать сервер, написать Desktop клиента, добавить язык в браузеры.
Комментарии (34)
amarao
11.04.2019 10:24+1Разумеется, в языках программирования всё хуже, чем хотелось бы. Но всё, что вы хотите, уже давно есть. Выбирайте — php, javascript — все они радостно будут «управлять типами данных» за вас. А вам останется всего лишь написать логику программы для обработки undefined'ов.
В то же самое время высшие достижения индустриального языкостроительства фокусируются на более богатом синтаксисе типов. Алгебраические типы данных, предикаты на типах (их иногда называют трейтами или типажами), зависимые типы данных и т.д.misha_shar53 Автор
11.04.2019 11:22Но это не значит, что богатство синтаксиса типов полезно.
amarao
11.04.2019 12:38Скажите, а зачем вам язык программирования? Например, какая польза от ООП, когда можно просто написать код? Вопрос о причинах существования языков программирования более интересный, чем кажется, потому что основную проблему, которую решают языки — это не «веб-сервер в две строки» (на ассемблере так тоже можно), а контроль типов.
Само существование типов данных (например, что «строка» и «число» — это разные типы) — это ограничение на то, что можно делать. В си, где эти ограничения слабые, вы можете сделать char x = 'а' + 1; и это будет валидным (хотя и означает невалидную ахинею, если a — русская в utf-8). Более благородные языки запрещают такие кульбиты без явного кастинга, т.е. лучше защищают программиста от ошибок.misha_shar53 Автор
11.04.2019 12:56Ограничения должны быть в голове программиста, а не в языке. Си конечно не предмет для подражания и в данном случае путаница возникает из за плохого синтаксиса Си. Операция сложения спутана с операцией соединения. В вашем примере это вполне нормальная операция с результатом 'b', а то что возможно вы хотели что то другое это к компилятору никакого отношения не имеет.
amarao
11.04.2019 13:43Если ограничения в голове у программиста, зачем вам язык программирования? Любой язык программирования умеет меньше, чем код на ассемблере (т.е. содержит ограничения).
misha_shar53 Автор
11.04.2019 12:26<Разумеется, в языках программирования всё хуже, чем хотелось бы. Но всё, что вы хотите, уже давно есть. Выбирайте — php, javascript — все они радостно будут «управлять типами данных» за вас. А вам останется всего лишь написать логику программы для обработки undefined'ов.>
Конечно есть MUMPS существует уже давно, нет хорошей реализации этого языка, да и некоторые конструкции этого языка устарели. Поэтому то я и занялся этим неблагодарным делом.
netricks
11.04.2019 10:33К сожалению, практика показала, что идеального языка быть не может (иначе бы он у нас уже был).
Так что, как по Абатуру: «Генетические цепочки не совместимы. Нужно выбрать.»
j8kin
11.04.2019 10:47+1Если в ассемблере все так прекрастно, зачем придумывать что-то новое?
Пассаж про статическую типизацию тоже огонь.
berez
11.04.2019 11:01Язык должен полностью брать на себя все управление данными, в том числе разбираться с их типами. Что вполне реально. А программист должен заниматься логикой программы.
Потом программист сидит и бьется головой о клавиатуру, пытаясь понять, в каком месте его программы данные из числа становятся строкой, и var + 1 вместо прибавления единицы к числу начинает приписывать единичку в хвост строки…
Передача параметров через стек. Надо просто отказаться от списка формальных параметров, а передавать параметры через какой либо список.
А извлекать эти параметры из списка потом как? По порядковым номерам? У — удобство!
Списки формальных параметров для того и придумали, чтобы не париться с нумерацией аргументов, а сразу иметь понятное имя.
Возвращать переменное число значений функции мне не совсем понятно для чего и как этим можно воспользоваться. Возвращать в любом случае надо какую то одну сущность.
Если вам непонятно — поиграйтесь с языками, поддерживающими возврат списка значений. Например, с Lua. Там можно вернуть, например, список из bool и какого-то значения: если bool == true, то в значении — полезная нагрузка, а если в bool лежит false, то это значит, что произошла ошибка, а вместо значения — дополнительные сведения об этой ошибке.
Небольшие нюансы возникают с использованием команды goto. Мне не понятно почему с таким остервенением борются с этой командой.
Потому что:
а) с помощью goto плюс if можно сэмулировать все структурные управляющие конструкции (циклы с пред- и постусловием, switch/case, и т.п.). При этом код воспринимается хуже (надо вдумываться, куда мы переходим и при каких условиях). Ну и ошибки легче допустить.
б) Очень легко превратить код в лапшу, в которой невозможно разобраться.
Чтобы понять, насколько хренов бывает goto, можно поиграть на досуге в старую игру на бейсике:
Начальный код:
10 LET A = 0
20 LET B = 0
1. Играют двое. Ходят по очереди. За один ход можно написать в программе (в свободной строке с любым номером, большим 30) одну строчку.
2. После каждого хода противник может заявить, что программа зациклена. Программу запускают и проверяют, что она действительно зациклена (т.е. не останавливается через оговоренное время — скажем, 30 секунд). Если да, то объявивший выигрывает. Если нет, то проигрывает.
3. Игрок А может писать одну из двух строк на выбор: а) LET B = NOT B, и б) IF A THEN GOTO xxx
4. Игрок Б, соответственно, может писать а) LET A = NOT A, и б) IF B THEN GOTO xxx
5. Цель для GOTO должна существовать.
По договоренности можно вводить другие допустимые команды (например, LET A = NOT B).
Как правило, уже в районе десятого хода программа превращается в фигпоймичокакработает и очень неплохо иллюстрирует, что такое спагетти-код.
Отладка простейшей программы на Си может занять месяца. И все это по моему мнению порождено типизацией в языках программирования.
Отладка простейшей программы на пыхпыхе тоже может занять месяца, если программист неопытный и не понимает, что творит. Я уж не говорю про ассемблер. Порождено ли это отсутствием типизации? Не уверен.
Кого заинтересовала моя работа пишите на почту, вышлю дистрибутив.
Уже лет десять как исходники можно выложить на какой-нибудь гитхаб. Заодно и желающие помочь смогут сразу включиться в работу над кодом.
Или вы думаете, что кто-то всерьез захочет использовать в коммерческом проекте интерпретатор неизвестного языка программирования, да еще и без исходников?roscomtheend
11.04.2019 17:26$_[0], $_[1] — в Perl всё придумано. Удобно — офигеть (когда не 1-2 параметра, память там развивется и прочие навыки), тем более первое, что делается:
local $par_name = $_[0] # или shift
И удобнее и нет доступа по индексу к массиву.
Автору же предлагаю заменить всё переменные на элементы одного массива и обращаться по номерам.
KvanTTT
11.04.2019 11:04Кого заинтересовала моя работа пишите на почту, вышлю дистрибутив.
Что за древний способ? Почему бы не выложить на GitHub?
Zanak
11.04.2019 11:19Уж не знаю, кто и чему вас учил, но я не согласен с вами.
Объектное программирование
Если в языке нет поддержки объектов, то ваше писание в объектном стиле выльется в реализацию недостающих моментов средствами самого языка. Иногда это оправдано, но не так часто, как вам хотелось бы.
Управление данными, типизация
Нет ни какого антагонизма между статической и динамической типизацией. Вопрос в выборе наименьшего зла и извлечения максимальной пользы из сделанного выбора. Php или perl выполняют неявное приведение типов, это позволяет не задумываться об этом разработчику, но дает побочный эффект, в виде, подчас трудноуловимых, ошибок. Python позволяет динамическую типизацию, вы можете в разные моменты времени присваивать одной и той же переменной значения разных типов, но контролирует тип при выполнении операций. Языки со статической типизацией позволяют избежать некоторого количества ошибок в процессе компиляции. Go и rust пытаются извлечь еще больше пользы из знания типов переменных в процессе разбора исходного кода. Более того, как минимум, php и python совсем не прочь научится фиксировать тип переменной в своем коде.
Управление процессом выполнения
Все архитектурные вещи лучше выносить в библиотеки, оставляя среду исполнения максимально гибкой и легковесной. Если есть подозрение, что появится потребность в тонкой оптимизации, предусмотрите FFI для вашего языка, хотя бы с Си. Это, к стати, упростит появление биндингов с большими и популярными библиотеками, которые с вас обязательно спросят, как только вы убедите кого либо использовать ваш язык.
FForth
11.04.2019 11:27>Надо просто отказаться от списка формальных параметров, а передавать параметры через >какой либо список
Вы про Forth (Форт) язык с отказом в нём от связи фактических и формальных параметров читали? (хотя в стандарте 94-года добавили и эту возможность).
С использованием стека, при этом, построено много конкатенативных языков.
P.S. Другие моменты в Форт тоже интересны.nad_oby
12.04.2019 12:15Вот сразу про форт подумал.
Когда на него смотрел почти достиг просветления.
Совсем немного не хватило.
phantom-code
11.04.2019 11:37Я не являюсь сторонником ни того, ни другого подхода.
Расскажите о вашем подходе, сторонником которого вы являетесь.
Я считаю типизацию как таковую основным злом современных языков программирования.
Приведите пожалуйста пример, как можно обойтись без типизации. Так или иначе, программе нужно «знать» формат хранения данных в памяти по определенному адресу.
Я вас не знаю и не знаком с вашими работами, но чисто субъективно, у меня создается ощущение, что у вас в голове какая-то каша.misha_shar53 Автор
11.04.2019 11:49Незнание не является аргументом. В моем тексте упоминается язык MUMPS. Он и является примером.
misha_shar53 Автор
11.04.2019 11:56Программе знать тип конечно необходимо. Но выносить это на программиста вовсе не обязательно. Я знаю по крайней мере 2 способа это реализовать. Любую переменную приводить к одному типу, либо хранить вместе с переменной ее тип.
phantom-code
11.04.2019 12:19Программе знать тип конечно необходимо. Но выносить это на программиста вовсе не обязательно. Я знаю по крайней мере 2 способа это реализовать. Любую переменную приводить к одному типу
Если все хранить в строках, о высокой производительности можно забыть, да и памяти это съест больше, чем могло бы.
либо хранить вместе с переменной ее тип.
А тут получается tagged union, использование которого похоже на эмуляцию динамической типизации средствами языка, ее не поддерживающего. Любой интерпретатор языка с динамической типизацией должен хранить значения переменных подобным образом.
По сути получается, что вы скорее сторонник динамической типизации и ваш язык программирования не подойдет для задач, требующих максимальной производительности.
misha_shar53 Автор
11.04.2019 12:05Я являюсь сторонником безтипового языка.
amarao
11.04.2019 12:41А почему вы вообще сторонник языка? Если вы сказали процессору mulps xmm0, xmm1, то он пошёл и умножил. Зачем плодить сущности и птичьи языки?
kuza2000
11.04.2019 12:00У динамической типизации преимуществом называлось гибкость языка, но недостатком якобы является ненадежность языка и плохая адаптируемость к средам разработки. У статической типизации все с точностью до наоборот. Я считаю доводы о лучшей надежности языков со статической типизацией абсурдными, возможно что статическая типизация помогает в разработке средств программирования, но не более того.
Одно из самых главных преимуществ статической типизации — это возможность генерации максимально быстрого машинного или байт кода. Сложение двух целых чисел со статической типизацией будет занимать одну (!) машинную команду. При динамической типизации среда исполнения выполнит ряд плясок вокруг значения, на тему: «а что там лежит? а с чем это складывать? а тип операции допустим для первого типа? а для второго?». Это значительно ухудшает быстродействие (на порядок — запросто).
Есть и другие преимущества, например со статической типизацией переменные можно размещать в стеке — это еще плюс быстродействию и экономии памяти. С динамической типизацией в стеке можно поместить лишь указатель, а сама переменная будет в другом месте, и выделить под нее памяти — это опять куча танцев у менеджера памяти, а потом и у сборщика мусора. Для выделения памяти в стеке требуется снова одна-единственная машинная команда, причем на все переменные разом. Сбор мусора для переменных в стеке не нужен в принципе, это опять экономия ресурсов.
PS: А на MUMPS я работал, и даже писал интерпретатор подобного языка.misha_shar53 Автор
11.04.2019 12:12Ну тогда вы должны быть в курсе. Я не оспариваю преимущество типизации для трансляторов, они очевидны. Но считаю, транслятор должен быть для программиста, а не наоборот. Для скорости надо писать на Ассемблере.
berez
11.04.2019 12:17Для скорости надо писать на Ассемблере.
Очень сомнительное утверждение.
Если вы не гуру AVX512 и прочих хитрых расширений, то любой оптимизирующий компилятор С уделает ваш ассемблерный код как по скорости работы, так и по скорости разработки.kuza2000
11.04.2019 12:44По быстродействию — спорно. Если уж взялся за ассемблер, то знание всех возможностей процессора подразумевается :) Иначе — зачем?
А по скорости разработки — конечно.berez
11.04.2019 13:03Если уж взялся за ассемблер, то знание всех возможностей процессора подразумевается :)
Человек, в отличие от машины, гораздо хуже просчитывает такты, которые занимает та или иная инструкция. Особенно с учетом всяких привходящих обстоятельств: кэшей, пайплайнов, наличия/отсутствия отдельных блоков для распараллеливания инструкций, предсказания переходов и т. п. В результате код, написанный человеком, может быть компактнее, но при этом выполняться медленнее, чем сгенерированный оптимизирующим компилятором.
Вот если компилятор староват и не умеет, скажем, использовать векторные инструкции — тогда да, ассемблер ручной выделки может в разы увеличить производительность. Но в общем случае компилятор забарывает человека.
kuza2000
11.04.2019 12:38Если бы для скорости писали на ассемблере, ты Вы бы жили в совсем другом мире. Большинство операционных систем было бы не создано.
Для скорости надо писать на языках, близких к машине. Это C/C++. Быстродействие программ, написанных на них, не уступает ассемблеру (за исключением редких специальных случаев). И их быстродействие обусловлено, в том числе, статической типизацией.
Вообще, я не против языков с динамической типизацией. Мне, например, нравится Питон. Но каждый класс языков хорош для своей задачи.
Нужен максимум быстродействия и полный контроль над железом — выбираем C/C++, где-то, возможно, Ассемблер.
Нужно писать миллионы строк для интерпрайза — для этого хороши C# или Java.
Быстро сделать скрипт или прототип — неплох Питон.
Ну и т.д.misha_shar53 Автор
11.04.2019 12:46Полностью с вами согласен. Си конечно быстр, но очень далек от идеала. Хотя это связано не только и даже не столько с языком, сколько с окружающей инфраструктурой.
roscomtheend
12.04.2019 09:44Для скорости надо писать на Ассемблере.
Что быстрее — dec+jnz или rep?
Я не оспариваю преимущество типизации для трансляторов
Трансялятор — далеко не единственная вещь, любой расчётный софт требует производительности, ваш язык получается неким эзотерическим языком с нулевой практичностью, тем более интерпретатор в настоящее время тоже не особо полезен. Непонимание что будет результатом оператора сложения для программиста хуже, а не лучше. Вы заявляете что "транслятор для программиста", но получается ровно наоборот, если брать автомобили, то у некоторых такие роботизированные коробки, которые по заявлению созданы для облегчения, но по факту надо подгадывать момент их переключения и подстраиваться под него, иначе будет рывок. Так и у вас — у нас нет типа и надо дополнительно ещё и представлять что получим в каждой конкретной операции.
misha_shar53 Автор
12.04.2019 17:44Расчетные задачи не самая сильная сторона MSH. Все MUMPS системы разработаны для создания больших информационных систем. Там они и используются. Все используемые MUMPS системы интерпретаторы и этому есть серьезные причины. Часть конструкций этих языков не могут быть оттранслированы в принципе. MUMPS языки это не экзотика, а повседневный рабочий инструмент. То что MSH будет востребован сомнений нет. Просто для языка надо создать экосистему. Это дело труда и времени. Как только экосистема будет создана, с той минуты он и начнет использоваться. Есть достаточно большое сообщество которое в курсе о чем идет речь.
misha_shar53 Автор
13.04.2019 06:14Результатом сложения всегда будет число, так как это арифметическая операция. Операцией сцепления всегда будет строка, так как это операция строковая. А при манипулировании данными вообще тип переменной не имеет никакого значения.
roscomtheend
15.04.2019 13:39«1»+1, «a»+1, «1»+«1».
Программисту придётся задумываться что получилось в результате прошлой операции и что может быть в текущей, в «больших информационных системах»(больших по сегодняшним меркам) может быть много неожиданностей от этого.misha_shar53 Автор
15.04.2019 14:28Думать как раз не надо. В MUMPS все всегда однозначно:
«1»+1=2,
«a»+1=1,
«1»+«1»=2.
Всегда так. В арифметической операции «a» = 0, а «25aw7/9» = 25
И никаких неожиданностей быть не может.
podivilov
Зачем?