пятница, 20 мая 2022 г.

Шеркало 06: красный свет

 - Шеркало, где я? Что со мной?

- Откуда я знаю? Ты же последние три месяца тёмную тень с глаз не снимаешь, что же я могу увидеть вокруг тебя?

- Почему все вокруг сошли с ума? Или это я сошёл с ума?

- Ммм?

- Сегодня вышел гулять на улицу. Обошёл несколько соседних кварталов. На каждом встреченном по дороге перекрёстке, кто-то из прохожих переходил дорогу на красный светофор.

- Ну и что? Бывает...

- Нет, Шеркало, ты не поняло. Я сам знаю, что бывает.

Бывает, что человек торопится, по какой-то причине думает, что у него каждая секунда на счету. Не важно, оправдано ли его мнение, или ему лишь кажется, что сейчас следует торопиться любой ценой, важно, что он искренне верит в то, что его цель его торопит, и эта цель оправдывает все средства. Да, такое бывает, это, как правило, всегда хорошо заметно.

Ещё, бывает, встречаются люди (обычно старые бабки), которые с советских времён твёрдо усвоили, что во всех приличных местах их всегда обязаны пропускать строго без очереди, как признанных ветеранов Ледового Побоища 1242 года или Куликовской Битвы 1380 года. Ну и они автоматически относят перекрёсток со светофором к подобным "приличным местам". Для таких людей подождать зелёный сигнал светофора - это даже своего рода "западло", это значит самому по собственной воле унизить себя, принизить собственную значимость и занизить собственный возраст. 


Но сегодня почему-то было совсем не то. Обычно подобных "торопыг" встречаешь за день считанные единицы. Большинство людей всё же нормальные, на светофор глядят, дуром под поток машин не лезут. А вот сегодня - вдруг что-то особенное. На каждом, буквально на КАЖДОМ перекрёстке. Если не каждый первый, то уж каждый второй встречный точно!

На первом же перекрёстке встал на светофоре, жду зелёный свет. Мимо спокойно проходит немолодая женщина. Никуда особо не торопится, собственную значимость не показывает. Ей просто глубоко пофигу, что там на светофоре, благо на поперечной улице машины уже почти закончились.

На следующем перекрёстке навстречу мне на красный свет также спокойно проходят две девушки студенческого возраста. Но эти традиционно не отрывают взгляд от телефонов, по сторонам им смотреть некогда, на светофор тем более.

Очередной перекрёсток, очередной молодой парень тоже студенческого возраста. Ему нужно было перейти перекрёсток по диагонали, через две перпендикулярные улицы - можно сначала налево, потом направо, а можно наоборот, сначала направо, потом налево, по расстоянию безразлично. Он уверенно зашагал прямо, никуда не сворачивая на красный свет. По улице в это время ехали машины, тормознули, хором возмущённо забибикали. Парень не оборачиваясь отмахнулся рукой: "Заткнитесь, придурки!!!". Когда он закончил переходить улицу, сигнал светофора как раз успел смениться на противоположный. Парень тут же повернулся и пошёл переходить вторую, перпендикулярную улицу, где только что ему зажёгся красный свет. Почему он не стал пересекать перекрёсток в обратном порядке, чтобы попасть на зелёные сигналы, для меня полная загадка.

Новый перекрёсток - взрослый мужик, интеллигентного вида, даже без телефона в руке, никуда не торопясь, как обычно на красный, как обычно тормоза и бибиканье. Последний на маршруте моей прогулки перекрёсток - молодая женщина, не совсем интеллигентного вида (почему-то в болоньевой куртке с накинутым капюшоном, хотя на улице солнечно и жарко), но тоже без телефона... туда же, на тот же светофор.


- Слышь, Ёж, а может ты дальтоник?

- Во-первых нет, Шеркало, а во-вторых, верхний сигнал с нижним у светофора, я по-твоему тоже путаю?

- А может ГосДума издала новый закон, что в связи с политикой импортозамещения теперь нельзя руководствоваться сигналами светофоров, разработанных по недружественным международным стандартам, а ты этот закон пропустил?

- А может проще предположить, что кто-то сходит с ума?

- Может, осталось выяснить, кто именно.

- Так я с этого и начал разговор...

пятница, 28 января 2022 г.

Шеркало 05.10: (не)любимые системы программирования (Другие ч.4)

- Ёж, какая сегодня погода?

 - Так, Шеркало, не отвлекай меня! Эту серию про системы программирования, пора уже жесточайшим образом заканчивать, тем более, что любимые давно закончились, а нелюбимые, большей частью, не особо интересны!

- Ну и пожалуйста, ну и заканчивай, себе, на здоровье.

C++

Про язык C++ конечно тоже нельзя не упомянуть. Тем более, что это совершенно самостоятельная среда и даже совершенно отдельная "экологическая ниша", по сравнению с исходным языком Си. Это не просто объектно-ориентированное расширение Си, это вообще отдельная парадигма программирования. Картинок, с исходными текстами наверное в этот раз не будет. Ни  к чему они, в моих воспоминаниях. Если Си я в прошлый раз оценивал, как "структурную надстройку над ассемблером PDP-11", то C++ безусловно с ассемблерами, да и вообще, с любыми предыдущими языками (включая даже язык Си!!!), сравнивать нельзя!

C++ есть воплощенная бескомпромиссная производительность и мощность программирования, выжимаемая из архитектуры современных микропроцессоров! Это язык, на котором программист должен иметь возможность написать ВСЁ, что пожелает, реализовать любые, самые смелые свои фантазии! На момент разработки C++ передовой технологией считалась (была, на самом деле) технология Объектно-Ориентированного Программирования (ООП). C++ вобрал в себя парадигму ООП по самому максимуму! Чего стоят только реализации множественного наследования, и перегрузка функций, и перегрузка операторов!!! Главная идея - всей мощности и свободы побольше, побольше, и ни в чём, кроме размера виртуальной памяти (которая почти бесконечна), не нужно себя ограничивать!

Моя личная работа с C++ не сложилась точно так же, как и работа с Си. Те же, самые достоинства, языка, что и у Си, только возведённые в третью степень. Те же самые недостатки, что и у Си, тоже возведённые в третью степень. Тот же самый мой вывод: Паскаль (на этот раз более современный Object Pascal, поддерживающий ООП) - гораздо проще и понятнее. Пусть у меня с Паскалем не будет всемогущей власти над всеми современными нюансами программирования, но зато я и не буду неделями выискивать в программе (особенно в чужой) кучу неприятных блох, появившихся в результате единичной случайной опечатки в одном символе текста.


Бейсик BASIC 

Тоже, вероятно надо упомянуть.  Изначально - учебный (поэтому очень сильно сокращённый вариант Фортрана). Выглядел примерно вот так:

10 INPUT "Введите значения X1,X2,X3,B,A"; X1,X2,X3,B,A
20 LET X=X1
30 LET Y=(B*X^2-A)/(EXP(A*X)-1)
40 PRINT "X=";X;"Y=";Y
50 LET X=X+X3
60 IF X<=X2 THEN 30
70 END
В качестве учебной версии Фортрана на период начала1960-х годов - идеальное решение, буквально по всем параметрам! Здесь нужно отметить, обязательную нумерацию строк. Это, с одной стороны, прямое наследие Фортрана (но в Фортране не все строки обязаны были иметь номера). С другой стороны, нумерация строк - очень существенное облегчение при реализации экранного текстового редактора (ВАУ! А читатели вообще в курсе, что ЭКРАННЫЙ текстовый редактор для ранних персоналок был недостижимой мечтой?! Что текст редактировался в лучшем случае в пределах одной строки, пока не нажата кнопка ENTER/ВВОД?! А потом - ищи-свищи эту строку!) на слабом компьютере (на тот момент, опять же, почти идеальное решение, позволяющее создать прямо на коленке приличный экранный текстовый редактор из примитивного строчного текстового редактора - очень простое (редактирование ранее введённой строки по её обязательному номеру) и удобное решение при разработке интерактивного интерпретируемого (построчно) языка на компьютере, который ещё толком не поддерживает полноценные полно-экранные терминалы.

Маленькая  техническая вставочка. Изначально под термином "терминал" (извините за невольную тавтологию) на больших компьютерах, подразумевался телеграфный аппарат. Ты ввёл строчку текста, она отпечаталась на бумаге (или, чаще на бумажной ленточке с клейкой основой), и после нажатия кнопки "Передать" ушла в компьютер. Тот немного подумал, подумал, в ответ выдал тебе на бумаге (ленточке) свою ответную строчку символов.
Вот и всё! Вернуться к предыдущей строчке и исправить её, если где-то опечатался, уже НЕЛЬЗЯ. Предыдущей строчки уже в компьютере физически НЕТ, она сохранилась только в форме строки букв, отпечатанных (перфорированных) на бумаге. Вернуть эту строку букв обратно в компьютер, чтобы исправить опечатку, уже никак нельзя, она уже вышла оттуда, она уже "wasted". (На самом деле можно, но сложно, и я сейчас говорю не об этом).
Ну и вот, идея жёстко пронумеровать каждую вводимую строку (при этом сохраняя копию этой строки в памяти компьютера!) позволяла обеспечить редактирование текста программы в интерактивном режиме - каждую строку редактировали, назвав её уникальный номер! Ну и плюс,, вспомним тот же FORTRAN, с которого BASIC брал пример - там тоже изначально каждая строка на бланке для пробития перфокарт свой номер имела. Только потом разрешили у "неважных" строк, на которые никто не ссылается, номера пропускать. Так, в исключительно строчном режиме, обходили технические ограничения терминалов на редактирование предыдущих (уже ушедших из короткого буфера памяти терминала) строк.

Как только терминалы больших ЭВМ, работавшие в режиме буквопечатающих телеграфных аппаратов, перестали быть супер-уникально-актуальными (где-то в конце 1970-х годов) и сменились полноэкранным редактированием текстов, так тут же язык BASIC начал очень быстро совершенствоваться. Прежде всего исчезла обязательная нумерация каждой строки, появились символьные переменные и операции с ними. С приходом микрокомпьютеров и ПК в язык включились низкоуровневые функции, элементы ООП, готовые библиотеки программ... Огромную роль в развитии BASIC сыграла фирма Microsoft, во главе с известным всему миру программистом Биллом Гейтсом. В своё время фирмы Microsoft и Borland даже, по слухам, очень круто поцапались друг с другом именно из-за языка BASIC. Итогом конфликта стал раздел сфер влияния: Борланд прекратила развивать свою успешную тогда линию компиляторов "Turbo Basic", отдав это поле Майкрософт. В свою очередь, компания Гейтса отказывалась от претензий на компиляторы языка Паскаль, признавая их сферой интересов Борланда. 

Дальше о BASIC - всё просто. Для изначально слабых ПК на базе ранних 8 и 16 разрядных процессоров, BASIC (тем более в относительно современных инкарнациях). был одним из немногих реально эффективно реализуемых на том железе языков высокого уровня. Тем более, будучи при том  изначально простым для понимания начинающими, BASIC получал всё более нарастающую популярность. размножался во множестве версий и пользователей. Немного позже, с появлением полноценных 32, 64 разрядных ПК, BASIC утратил какие-либо специфические преимущества. гораздо более простые, удобные, понятные, развитые языки программирования стали завоёвывать бОльшую популярность.
От полного забвения BASIC спас лично Билл Гейтс, испытывавший к этому языку свою личную симпатию. Он сделал именно BASIC, в варианте Visual Basic for Application (VBA), основным скриптовым языком сверх-популярного пакета программ MS Office, что безусловно продлило жизнь языка на несколько десятилетий (а потом ещё в оболочке PowerShell тоже танцы с BASIC продолжились и до сих пор продолжаются). Но, как и во многих иных случаях, то что понимается по Basic'ом сейчас к изначальному языку BASIC из Дартмутского колледжа не имеет практически никакого отношения - ни единой общей чёрточки, совсем ничего похожего, кроме нескольких общеупотребительных служебных слов, знаков арифметических операций и арабских цифр.

Моё мнение о BASIC: для маломощных ранних ПК - он самое ТО, что тогда и надо было! Для скриптового языка MS Office, в меньшей степени для скриптового же PowerShell - он на своём месте, хотя могло бы быть и гораздо лучше. На перспективу - да ну его, нафиг, явно устарело.

- Так, я бегу. Шеркало, бегу быстрее, стараюсь пропустить мимо внимания галопом всё, что возможно. Но не могу пропустить язык Forth.


Forth

Нельзя его пропустить, поскольку Forth - идеальная классическая стековая машина. Что такое стек? Точнее, что такое LIFO-стек (Last Input - First Output) - это такая специальная "несправедливая" очередь - кто последним в очередь встал, обслуживается самым первым. Классический пример стека - магазин к автомату Калашникова, в котором самый последний заряженный патрон, оказывается на самом верху и выстреливается первым, а самый первый из патронов наоборот спускается при зарядке в самый низ магазина, и стреляет последним. Или узкая трубка с конфетками, открытая только с одного конца. Конфетки засыпаются в трубку сверху по одной, съедаются потом тоже по одной, начиная с самой верхней, последней конфетки, далее по порядку до самой нижней, самой первой.
Зачем такая "несправедливая" очередь нужна? Очень просто - экономия аппаратуры машины на адресации. В обычных компьютерах нужно тратить ресурсы (место в памяти, в машинных командах, в регистрах, на адреса операндов. Вроде "взять число из ячейки памяти 9876 и сложить его с числом из ячейки 4567, результат записать в ячейку памяти 2233". На все эти номера ячеек нужно тратиться, хранить их, декодировать, передавать из одного устройства процессора в другое и т.п. А в стековой машине ничего подобного не нужно. Адрес ячейки, откуда нужно взять первое число ВСЕГДА точно известен - это вершина стека. Адрес второго числа... вы будете смеяться, но он ТОТ ЖЕ САМЫЙ - это снова та самая вершина стека, откуда мы только что взяли первое число. Только там, на вершине, теперь лежит другое число, вот его и возьмём. Куда положить результат? Вопросов нет - ТУДА ЖЕ, на вершину стека. Нам при этом ни разу не понадобилось обращаться к ячейкам памяти напрямую по их номерам/адресам! Экономия, однако!

Так вот, Forth - это классическая стековая машина, где всё что можно хранится в стеке, поэтому прямая адресация памяти по номерам ячеек почти и не используется. Данные в Forth лежат в стеке, программа, на Forth, состоит из "слов", которые лежат откомпилированные в словаре, который на самом деле тоже хранится в стеке (модифицированном, наложенном на линейную память). Собственно и самого языка Forth, просто не существует! Forth - это набор слов, которые оперируют стековыми данными и виртуальная машина, которая слова из стека читает и интерпретирует. Слова из словаря, в виде стека, который может дополняться программистом. Программирование на Forth - это и есть дополнение уже готового словаря новыми словами сверху. Всё, что может быть представлено стеком - всё это и есть в стеке (а что нельзя положить в стек, то всё равно, хотя бы частично, но тоже хранится в стеке). Очень красивая парадигма!
На первый взгляд слегка шокирующим для начинающих становится первое же следствие стековой архитектуры - простые арифметические выражения приходится записывать в так называемой "постфиксной или обратной/инверсной польской" записи. Да и дальнейшее  программирование тоже требует... эээ... постфиксного подхода к написанию текстов. Но привыкнуть можно.

В Forth нельзя написать умножение, как
2 * 3  - операция умножения * здесь написана слишком рано - в стеке ещё нет готовых для неё чисел, правильно нужно написать вот так:
2 3 *  - сначала в стек складывается число 2, потом поверх него складывается число 3. Потом появляется операция * умножить. Она берет с вершины стека по очереди два необходимых операнда, сначала берёт 3, потом берёт 2, потом умножает их друг на друга и результат снова кладёт в стек, на его вершину.
А что бы выполнить математическую операцию  sin((a+b)/(c-d)) в Forth нужно записать такое выражение:
a b + c d - / sin
Понятно? Вполне красиво, и никаких скобок не требуется.
Хи-хи (оно же P.S.). Нужно отметить, что ничего не даётся бесплатно! В постфиксных выражениях Forth каждый лишний уровень скобок или учёт приоритета операций "обычного" выражения требует +1 к глубине стека.

Пример: выражение c + a * b запишется в постфиксной записи c a b * +. Хотя скобок и нет, но приходится из-за приоритета умножения, сначала положить в стек сразу ТРИ числа c a b, потом выполнить умножение a на b, вернув результат в стек поверх ранее положенного c, а уже потом сложить с с этим результатом.
Со скобками, меняющими порядок действий, всё аналогично. Выражение a * (b + c) в постфиксной записи будет выглядеть a b c + * и так же потребует стека глубиной не менее трёх элементов, в отличие от стека глубиной 2, достаточного при отсутствии скобок и приоритетов операций..

Такая же постфиксная логика математических вычислений была реализована и и известной линейке советских программируемых калькуляторов Б3-21, Б3-34, МК-52, МК-61 и некоторых других  У меня такие калькуляторы были ещё со школы (и даже сейчас есть - МК-61). Очень нравились, вполне удобно считать (по моим современным ощущениям, у МК-61 индикатор явно мелковат по размеру (в смысле физически мелковат, в миллиметрах), да и по яркости слабоват, но это уже личные придирки, сам принцип интересен и вполне применим). Отдельную статью об их программировании вряд ли стану писать. Упомянуть, что близкие по возможностям американские программируемые калькуляторы появились раньше, вероятно имеет смысл.  Но последующие исследования показали, что наши советские модели программируемых калькуляторов с постфиксной арифметикой создавались "по мотивам" (вот нарисуйте так, чтобы считалось прям как у них!), однако технически были вполне самостоятельны, и на уровне микроэлектроники - абсолютно несовместимы с "прототипами-вдохновителями" от фирмы HP..

С показыванием программ на Forth у меня возникли некоторые трудности. Ну нечего там показывать, для человека, смотрящего со стороны? Это же просто текстовый бред какой-то. А пояснять более подробно - так тут уж целые книги цитировать надо (при подготовке этого этюда я реально и с интересом перечитал пару умных книг по программированию на Forth). Попробую уложиться в формат рассказа?
: FACT                        (... n -> ... n!               )
  DUP 2 < IF DROP 1           (1 если n<2, то n!=1           )
  ELSE                        (n иначе                       )
  DUP                         (n n s=n k=n                   )
             (Теперь лежащие в стеке числа будут представлять)
                (s - накопленное произведение и k - множитель)
  BEGIN                       ( s  k                    <--  )
  1-                          ( s  k' k'=k-1               | )
  SWAP OVER * SWAP            ( s' k' s'=s*k               | )
  DUP 1 =                     ( s  k k=1 если k=1, то s=n! | )
  UNTIL                       ( n! 1 иначе повторить    ---  )
  DROP THEN ;                 ( n!                           )
Или более интересный вариант:

- Ты, Ёж, тут хвостиком своим куцым не виляй. Прямо говори, чем тебя Forth не устроил!

- Понимаешь, Шеркало... Дело не в том, что устроил или не устроил. 
Forth - наиинтереснейший язык, это вещь, которую ОБЯЗАТЕЛЬНО нужно изучать! Must Have, что называется. На базе идей стековой машины Forth и "шитого кода" (сознательно эту штуковину не упоминал для сокращения статьи) развивалось множество современных концепций ИТ и множество очень известных, популярных и сейчас систем. Forth - безусловно красивый прорыв для своего времени! Вот только... это НЕ язык программирования.

На Forth нельзя (точнее можно, но крайне неудобно и никто этого не делает) писать программы, работающие на каких-то общеупотребимых компьютерах, под управлением каких-то известных операционных систем, в среде кучи других программ под эту же систему. Нет, Forth - сам себе компьютер и сам себе операционная система. На нём нельзя просто взять и "написать программу". Нет такой опции! Вместо программы можно написать расширение самого языка Forth - любая программа, это не просто сторонняя программа - это именно расширение (усовершенствование) самого языка. Получается, что средний программист не может просто писать обычные прикладные программы, а должен для достижения своих прикладных целей дорабатывать используемый им язык программирования! Представляешь? Надо тебе, допустим, написать программу находящую корни квадратного уравнения или считающую площадь прямоугольного треугольника. А ты вместо этой примитивнейшей задачи, пишешь фактически свою собственную расширенную версию языка программирования!!! Всего-то на всего! Писал простенькую программку, а написал в итоге новый язык!

Ну и "лёгкий" побочный эффект: допустим некий абстрактный Вася, доработал Forth одним образом, чтобы реализовать сравнительно сложную матричную арифметику, а некая Маша доработала свой Forth таким образом, чтобы её респонденты заполняли красивые формы данных, которые потом могли бы использоваться при матричных вычислениях Васи.
И вот Вася с Машей, находят друг друга, понимают, что Машина программа могла бы насобирать данные, которых так не хватало Васе, а Васина программа, в свою очередь, могла бы обработать данные, которые насобирала Маша. Но тут выясняется, что Маша с Васей имели вообще разные взгляды на перспективы доработок Forth, что их собственные версии языка вообще даже близко несовместимы друг с другом, что у них разная арифметика, не говоря уже о разных границах массивов (у Васи с 0, а у Маши с 1), что для приведения всего этого цирка с конями к единой схеме требуется целый институт научных работников... Ну, в общем, пример исключительно надуманный, но понятно, о чём я толкую - поскольку программы на Forth как таковой не существует, все свои наработки можно сохранить только вместе с полным словарём языка. И что делать, если этот словарь оказался вообще разным у разных программистов, что неизбежно, даже в простейших случаях?!

Предложения сохранять новые слова в виде исходных текстов (как в моих примерах выше) и компилировать их позже в других системах Forth'а не помогают. Дело даже не в том, что в Forth есть огромные проблемы с файловыми операциями (хотя они традиционно таки там есть). Слова компилируются и отлаживаются в конкретной системе, в своей программной среде - это идеология языка. В общем случае, выдрать часть слов из системы Васи, и откомпилировать их в системе Маши, или наоборот, не получается, возникают сложно уловимые проблемы с отладкой, с дублированием и перегрузкой чужого кода. Перенос исходного кода проходит почти безболезненно лишь в очень простых (либо учебных, либо вырожденных) случаях.

Для чего действительно удобен Forth? Разработка очень кратких, предельно эффективных программ в условиях маломощных процессоров и при катастрофической нехватке памяти (вроде своеобразного ассемблера для маломощных машин с преимущественно стековой адресацией). Но, при этом, отсутствие требований к "универсальным" программам, сосредоточенность на типовых, повторяющихся операциях. Что за ниша? Управление аппаратурой, промышленные контроллеры. Вторая ниша - виртуальные машины, когда стековая архитектура дико удобна (экономна), а стековые недостатки никого не волнуют, люди сами вручную программы для стековых машин не пишут.
Для живого человека - стековая архитектура Forth обычно не самый лучший мнемонический вариант написания программ. 

Мой личный опыт Forth (не считая чисто "книжного") это - конечно БК-0010/11(М). Вроде бы условия как раз подходящие - компьютер с чудовищно обрезанной до смешных 15.5 кБ оперативною памятью. И Forth на нём с любовью реализован (на самом деле он был реализован на других клонах системы PDP-11, но на БК-0010 тоже вполне запускался). И неутешительный вывод - работает крайне нестабильно (слишком ограниченная аппаратная поддержка стека), чудовищно неудобен, программы плохо переносимые даже между однотипными системами. С трудом подходит для чисто учебных целей на самом младшем уровне начинающих, вроде "посчитайте 2 + 2 и выведите строку 'HELLO' задом-наперёд" (но тут для начинающих, ожидаемо, постфиксная запись категорически обламывает им всю малину), но ничего хоть чуть-чуть серьёзного реализовать не получается. К такому же мнению единодушно пришли и другие программисты БК-0010. Родной ассемблер PDP-11 на сто порядков лучше, проще, удобнее, надёжнее.

- Всё, наконец уже, Ёж?!
- Нет, Шеркало, потерпи, осталось совсем чуть-чуть, буквально несколько абзацев. Не хочу растягивать повествование на ещё одну часть.

Simula-67, Smalltalk

Не могу же я вот так всё завершить цикл рассказов, не упомянув про языки - родоначальники парадигмы Объектно-Ориентированного Программирования (ООП)? Традиционно самым первым языком ООП считается язык Симула-67, в котором впервые были реализованы большинство синтаксических (и семантических) идей современных ООП-языков.
Симула - расширение известного языка Алгол-60, в который в первую очередь были добавлены классы - некие структуры, которые объединяли внутри себя данные (переменные, поля) и исполняемый код (процедуры, методы, оперирующие с этими данными). Классы могли наследовать свойства друг друга. В программе динамически порождались отдельные экземпляры - объекты описанных классов. Всё это предполагалось для того, чтобы как можно точнее моделировать (точнее симулировать, отсюда и название языка "Симула") объектами в программе поведение настоящих объектов реального мира.

Я в своё время (опять же в школьное время) на Симулу-67 внимание конечно обратил. Купил в магазине книжку про этот язык. Внимательно её прочитал. Идея объединять в единое целое специфические внутренние данные и работающий с ними код показалась здравой и интересной, но приведённые в книжке примеры меня особо не впечатлили. Вроде как с объектами, чуть нагляднее получается, но смысл огорода не совсем ясен, как бы и без объектов всё то же самое можно было и обычными средствами сделать почти не хуже. Повторюсь - это всего лишь моё личное впечатление от прочтения книжки-брошюрки, по сути - учебника. Книжка при очередном переезде конечно потерялась. Доступной реализации Симулы я так и не нашёл (хотя специально и не искал), так что на практике этот язык никогда не пробовал.
Много позднее вернулся к теме ООП уже при работе с TurboPascal и Delphi - вот там реально понимание объектно-ориентированной парадигмы понадобилось на практике. Ещё обратил внимание, что название одной из известных книг неоднократно упомянутого профессора Вирта - "Алгоритмы + Структуры данных = Программы" очень здорово перекликается с идеей Симулы-67. Пример того, что иногда востребованные идеи просто "витают в воздухе" и приходят в голову многим одновременно.

Примеров программ на Simula-67 приводить не буду. Во-первых, я ни строчки на этом языке не написал, а во-вторых - Алгол, он и есть Алгол, ничем на вид, кроме нюансов не отличается. Пусть желающие сами картинки ищут.

Другой язык, считающийся классикой парадигмы ООП - это Smalltalk, развивавшийся с начала 1970-х годов и оформившийся к началу 1980-х. В Smalltalk всё есть объекты, нет вообще ничего, кроме объектов. И эти объекты активно общаются друг с другом, обмениваясь сообщениями (которые на самом деле тоже есть объекты), и, реагируя на свои входные сообщения, собственно и реализуют логику работы программы. Объекты принадлежат классам, объединяющим похожие объекты. Логика поведения объектов (программный код) сохраняется в классах, а вот индивидуальные особенности - конкретные данные, сохраняются в индивидуальных объектах. Но классы, в которых сохраняется код, а не данные, тоже, разумеется, являются объектами...

- Хрррр-пшшшшш-хррр-хрр-пшшш-пуфф-хррр!
- Шеркало?!!!
- А, Что? Я всё слышал! Вот, смотри: "язык Forth является неотъемлемой структурой программы объектно-функционирующей при получении данных для системы класса 8-б Васи от PDP-11, которая у Маши в классе 7-г вместе с симуляцией". Я всё правильно понял?
- Э... Шеркало, а как будет звучать термин "ИДИОТ", несли его применить к существительному среднего рода?
- Ёж, давай уже, заканчивай, и не выёживайся!
- Даваю!

Не было у меня на практике никакого Smalltalk. Его вообще практически не было в нашей стране в то время (да и сейчас его тоже не очень). Но в мой университет ТГУ в связи с Горбачёвской "perestroyka" из самой Америки закупили целую партию сверхсовременных персональных компьютеров IBM PS/2. Их закупили аж 1.5 или даже целых 2 компьютерных класса. 
И где-то там, в недрах этих свежих, модных PS/2, затесалась какая-то ранняя PC-реализация языка Smalltalk. На нашей кафедре этот язык считали очень перспективным, пытались в том числе и меня к нему подвязать (примерно, как к Prolog и экспертным системам) из самых лучших побуждений. Вот только во-первых, нормальной русскоязычной литературы по нему в природе не существовало, во-вторых, стать моим научным руководителем по тематике работы со Smalltalk никто не спешил (как я понимаю, никто вообще этой тематики в университете и не знал, только самые любопытные ходили вокруг и облизывались, но всерьёз трогать боялись).

А в третьих... Ну почитал я рекламные проспекты. Потыкал мышкой в окошки. И бросилась мне в глаза такая деталь Smalltalk, которую я уже описывал в разделе про язык Forth.
Smalltalk - это НЕ ЯЗЫК программирования! Это целостная виртуальная система. На Smalltalk нельзя написать какую-то программу и отдать/продать её желающим пользоваться. Можно лишь взять уже готовую систему (виртуальную машину) и дорабатывать её своими собственными расширениями, чтобы в итоге получить другую виртуальную машину с изменённым функционалом, но зато не полностью совместимую с прежней. Соответственно, практическая польза от Smalltalk крайне ограничена, в основном академическими, учебными задачами, когда хочется поэкспериментировать с "чистым" ООП, без "прикладных примесей". Ну ещё он может быть полезен в тех областях, где заказчик желает вместо программы, решающей его конкретную задачу, получить (получить, оплатить, изучить, освоить и т.п.) целиком новенький полнофункциональный виртуальный компьютер, несовместимый с тем компьютером, который у него уже куплен под эту задачу, но по цене не менее дорогой, чем уже имеющийся.

Вот эти три препятствия, к разочарованию преподавателей, мне и помешали заняться Smalltalk. Я в момент учёбы в университете, да и позже тоже, был уже ориентирован на практически полезную работу, а не чисто учебные раскопки ради простого любопытства. Smalltalk практических результатов дать не мог, во всяком случае на моём уровне применения.
Примеров тоже не будет, по понятным причинам - я на этом языке не работал, и вообще это не язык, а виртуальная машина.

Ну и самое последнее, хочу упомянуть популярный язык Python, который мне в последнее время благодаря моим детям довелось попробовать. Нет, Шеркало, не беспокойся, писать о нём я здесь не буду. У меня уже был шуточный рассказ про Python, можно его перечитать. Добавлю лишь, несмотря на бытующее мнение о "простоте" Python, на самом деле, если копнуть чуть глубже, это весьма сложный, многослойный и достаточно запутанный язык.

ВСЁ.

суббота, 22 января 2022 г.

Шеркало 05.09: (не)любимые системы программирования (Другие ч.3)

 - Шеркало, помолчи, я продолжаю про свои системы программирования! Потерпи, уже вроде бы немного осталось.

- Ладно, молчу, я покладистое. Что следующее7

PL/1

- А это що такое?

- Ой, Шеркало, ты будешь смеяться, может быть, но PL/1 - это такой Алгол-68, только разработанный фирмой IBM по своему вкусу. Оба языка создавались почти в одно и то же время (PL/1 вышел на несколько лет раньше, но в ту же эпоху). Их разработчики варились, можно сказать, в одном соусе, вдохновлялись одними и теми же идеями, в процессе разработки активно общались и спорили друг с другом. Разработчики Алгол-68 кричали:

- Ваш PL/1 похож на новогоднюю ёлку - понавешали на разные ветки разных ёлочных игрушек, и радуетесь, а если внимательно посмотреть, ваши игрушки друг к другу по цвету и форме не подходят!

- А ваш Алшол-68, - возражали IBMовцы, - вообще практически никому в нашем еловом лесу не интересен! Пусть у вас все игрушки на всех ветках одинаковой формы, зато, у нас есть пулемёт у нас есть настоящая работающая IBM/360, а у вас её нет!

- Интересно, на чьей стороне была правда, Ёж?

- На мой взгляд, как обычно, и там, и там, или, ни там, ни там. Что касается, новогодней ёлки, то да, это правда PL/1 можно было сравнить с ней. Но, чья бы корова, как говориться мычала, а вот корова разработчиков Алгол-68, лучше бы в данном контексте молчала. Разработчики нормальных компиляторов Алгол-68 столкнулись с не меньшими трудностями, чем разработчики компиляторов PL/1 - и там, и там были много-много-проходные реализации, с многолетней отладкой/доработкой/переделкой компиляторов, со стыдливыми комментариями о "проблемах оптимизации" кода, о "вынужденных ограничениях" на точность реализации ранних версий стандартов. Одно другого стоит.

В целом же PL/1 был совершенно нормальным и ожидаемым языком. У фирмы IBM были FORTRAN и COBOL, которые, хоть и работали успешно и добротно, но справедливо критиковались за тяжеловесность и устарелость технологий программирования. Был пример Алгола и порождённых им языков, с красивой, продвинутой блочной структурой и перспективой подхода к функциям и рекурсии. И, самое главное, на подходе была совершенно новая, прорывная система компьютеров IBM/360, для которой как воздух немедленно требовался новый, потрясающий всех язык высокого уровня!!! Ну вот взяли, всё самое лучшее, что смогли найти в тот момент, сложили в одну общую мусорную кучу. Скрестили вместе бульдога (Фортран) с носорогом (Кобол), и с ёжиком (Алгол), и ещё с несколькими семействами летучих насекомых, чтобы уж совсем красиво было. Вот и получился PL/1, вполне, кстати, добротный язык программирования. Программы выглядели примерно вот так:

Наверное, не самая лучшая иллюстрация программы PL/1 - та серединка, где в начале строк идут цифры "1, 2" - это описание структуры записей данных, хранящихся во внешнем файле, заимствованное в PL/1 целиком из Кобола, а больше в программе почти ничего интересного и нет. Но, и так сойдёт. Я вообще, о личном опыте собирался рассказывать.


PL/1 нам начали преподавать на первом курсе Университета. Дело в том, что практику по программированию в Университете мы тогда могли проходить только на ЕС ЭВМ (ЕС-1033 была, если не ошибаюсь, но могу путаться, там позже более мощную ЕС включили). Ну, а для ЕС ЭВМ (которая, как известно, совместима с IBM/360), ничего более подходящего, чем PL/1 быть и не могло. Я на нём какие-то там учебные программки тогда тоже вместе со всеми писал. А в конце первого курса меня, как одного из призёров университетской олимпиады (в первой десятке студентов, в конце первой десятки из всего трёх десятков участников, ага), отправили в Новосибирский Университет (НГУ) на региональный этап олимпиады по программированию. 

А в НГУ всё устроили "по взрослому". Олимпиада проходила целых два дня. Нужно было выполнить с десяток заданий разной сложности, за которые начислялось разное число баллов. Часть заданий была теоретическими - ответ на бумаге, а часть практическими - написать программу и получить результат её прогона на реальном компьютере. Во втором случае начислялся или полный балл, если результат правильный, или строго ноль баллов, при любой ошибке (разумеется, ставились ограничения на время написания программы и на число отладочных запусков). Ну и, поскольку олимпиада региональная, а программирование везде преподавали по-разному, нам давали возможность выбрать язык программирования. Я взял, и выбрал свой любимый Паскаль. А все остальные студенты (из реально серьёзных претендентов на победу, не считая всяких деревенских маргиналов, второй раз в жизни клавиатуру увидавших), включая абсолютно всех новосибирцев, и всех томичей, кроме меня, выбрали PL/1. Потому что только на PL/1 и только для серьёзной ЕС ЭВМ и пишутся НАСТОЯЩИЕ серьёзные программы. А остальное - для лохов и сосунков.

В итоге я занял на той региональной олимпиаде второе место. За теоретическую часть (которая на бумаге) я получил ооочень средненькие оценки, или даже ниже среднего. Зато за практическую, компьютерную часть, я тогда получил наивысший возможный балл. Ну и мне запомнился разбор одной из практических задач, на чём погорели все остальные участники-фавориты.

Задача была очень простая, даже "детская". Программе на вход давалось множество точек на плоскости, каждая точка определялась парой координат (X, Y). И задавалась окружность с центром (X0, Y0) и радиусом R. Нужно было определить, сколько точек из заданного множества лежит внутри окружности, а сколько - снаружи. Всё было бы совершенно элементарно, если бы не один мааааленький подвох. В олимпиадном тесте количество точек внутри окружности превышало 40000 штук (т.е. 16-разрядного целого числа было недостаточно для их подсчёта).

У меня с Паскалем никаких проблем не возникло - компилятор работал на 32-разрядной ЕС ЭВМ, поэтому по умолчанию отвёл под счётчик точек переменную в 32 разряда. Этого с запасом хватило. А вот в PL/1 всё оказалось иначе. Там целые переменные по хорошему нужно описывать с явным указанием точности (это же одна из важных особенностей языка, делающая его воистину "профессиональным" - чтобы программист каждую спичечную головку, каждую копеечку, сам вручную к нужному месту присобачивал). В PL/1 переменную счётчика нужно было описать примерно так:

DCL  COUNT  FIXED BINARY(15);  /* целое 16 разрядов */

или так:

DCL  COUNT  FIXED BINARY(31);  /* целое 32 разряда */

а можно было написать и вот так:

DCL  COUNT  FIXED BINARY;  /* без явного указания точности */

но в последнем случае, компилятор сам про себя решал, что нужно взять самую короткую переменную (16 разрядов), чтобы сэкономить память. Так вот 100% студентов, писавших тогда в НГУ эту программу на PL/1 использовали либо первый вариант (потому что так писали в учебном классе - там память тоже учили по возможности максимально экономить), либо третий вариант (потому что вообще о точности не задумывались), и получали в результате целочисленное переполнение и отрицательное количество точек в круге, в ответе задачи. В итоге, я со своим маргинальным Паскалем оказался вообще единственным, кто правильно решил эту задачу! Оказалось, что для правильного результата мало выбрать "профессиональный" инструмент, нужно ещё и уметь его правильно профессионально использовать.

Ну а мой личный путь с PL/1 после Университета больше никогда не пересекался. Язык, как я уже сказал, получился достаточно добротный, хотя и сильно старомодный (переусложнённый синтаксис при отсутствии многих важных современным возможностей), но нигде кроме больших ЕС ЭВМ, у нас этого монстра никогда не использовали, а ЕС уже в начале 1990-х очень быстро вышли из употребления. Дальше PL/1 уже мало кого интересовал.


Язык Си.
- Ёж извини, что прерываю. А вот, мне кажется, или ты специально обходишь стороной, такой известный язык, как Си? Ведь, вроде бы, всё самое серьёзное, только якобы на нём и написано? А ты, всё сторонкой, сторонкой. да всё мимо...
- Си? Добро, Шеркало, замолвлю слово и за него. Утверждения, что "всё самое-самое только на Си", это конечно бред. С другой стороны - действительно ЭПОХАЛЬНЫЙ язык, без всяких шуток. в значительной степени повлиявший на синтаксис многих более современных языков, и что важнее, на развитие (как в положительном, так и в отрицательном смысле) современных парадигм программирования. А вот лично у меня с Си, в самом деле, к сожалению, интимные отношения не сложились. Мы с Си не пересеклись в нужном месте и в нужное время, а когда в итоге всё-таки пересеклись, то времена для влюблённостей уже миновали.

Затруднюсь выбрать пример короткой программы на Си. Разве, что уж совсем примитивный? Впрочем, это не имеет значения, сишные программы внешне выглядят всё равно, как почти любые современные программы. Ну, вот так пойдёт?

#include <stdio.h>

float power(float x, int n) 

  int ifloat s;

  s=1;

  for (i=0; i<n; i++) s=s*x;

  return s;

} 

int main() {

  float y;

  y=power(2.125,10);

  printf("Result: %f\n",y);

  return 0;

}


"Не сложилось" у меня с Си очень просто. В школьный период, когда я начал знакомиться с Си, он мне был весьма интересен, но вот попробовать запустить сишную программу я в ИОА тогда не мог - ни на БЭСМ-6, ни на М4030, доступных мне рабочих трансляторов Си тогда там не было. Изучать Си чисто теоретически "на бумаге" - вовсе неинтересно, это просто потомок уже известного Алгола, структурный и процедурный, что там такого особенного можно без доступа к компьютеру увидеть? В результате, я очередной раз прочитал очередную "умную книжку" про Си, принял её к сведению, временно забыл.

На практике Си стал мне доступен только в начале 1990-х, как в ИОА, так и в Университете, сначала на клонах архитектуры DEC PDP/VAX-11 (СМ ЭВМ, "Электроника", ДВК и т.п.), чуть позже на персональных компьютерах ПК (клонах IBM PC). Конечно же, я попытался к Си повторно приобщиться, ведь все программисты только о нём и говорят! И вот тут сработали два других негативных (с точки зрения любви к Си негативных) фактора:

1. К тому времени я уже хорошо знал ассемблер PDP-11, активно программировал на нём (БК-0010/0011(М)). И мне было абсолютно очевидно, что "знаменитый" язык Си - на самом деле всего лишь примитивная надстройка над ассемблером! Просто способ записать ассемблерный код PDP-11 в чуть более краткой форме, внешне напоминающей алгол-структурированную программу. Можно сказать, макро-язык поверх ассемблера. Сколь-нибудь опытный программист PDP-11 (я таким уже немножко тогда был) совершенно спокойно, прямо на невооружённый глаз, раскладывал любую программу на Си прямо в уме на ассемблерные команды: вот здесь будет такой комплекс команд, здесь вот такие условные и безусловные переходы, здесь вот такие режимы обращения к памяти и регистрам, автоинкременты, декременты не забываем здесь вот так вот задействуем стек. Всё, сделано, нафига тут нужен был какой-то Си?!
Опытный программист PDP-11 вообще в языке Си не нуждался! Это правда  Я сам лично был свидетелем! Ой! Чёрт! А Керниган? А он-то почему туда пош...?

2. Известно, почему. Там не только Керниган, там целая стая академиков подпевала! Говорили, что в результате анализа, стало известно, что 
а) итоговый машинный код программы на Си всего лишь на 5-10 % больше, чем код той же самой программы, написанной на ассемблере. Но вот, 
б) программа на Си содержит в 5-10 раз меньше строк, чем аналогичная ассемблерная программа. А психологи, с свою очередь, говорят, что 
ц) программист за один день может написать не больше 200 разумных строк (в среднем), абсолютно не важно, на каком языке.
Сопоставляем факты а) б) ц), и получаем очевидный (якобы) вывод - Писать программы на языке Си в 10 раз эффективнее, чем писать их на ассемблере. Очевидно же?! Количество строк в сутки = константа. Программа на Си занимает в 10 раз меньше строк, чем почти такая же программа на ассемблере. Вывод - писать программы на Си = в 10 раз эффективнее! В сутки средний программист может написать на Си в 10 раз больше кода, чем тот же программист на ассемблере! УРА!!! Все пишем программы на Си!!! Да? Что не так? 

Возражение очень простое: программист, он ведь не машинистка, которая тупо фигачит под диктовку по 200 нажатий клавиш на пишущей машинке в минуту, не разбирая, что она там фактически печатает. Программист обязан прежде всего думать над тем, что пишет. А количество строк - абсолютно вторично. А вот время и эффективность размышлений программиста, они никак в количествах строк в сутки не измеряются. И напротив, когда дойдёт время до записи текста итоговой программы в строках, там время на их набор займёт едва ли один процент от общего времени разработки программы, независимо от количества строк. Так стоило ли экономить на спичках?

3. Вернёмся от PDP-11 к более современным персональным компьютерам ПК. Там- то что меня в языке Си не устроило? Как ни смешно, ответ - язык Паскаль (о, моя любовь!) и фирма Борланд. :))
Дело в том, что та самая фирма Борланд, в раннюю эпоху развития компьютеров ПК (IBM PC) писала целые линейки разнообразных компиляторов с разных языков программирования. Эти компиляторы обычно выпускались по маркой "Turbo", при этом, несмотря на жутко самохвалебное название, трансляторы реально были продвинутыми и востребованными, на момент их выпуска. В линейке "Turbo" были и "Turbo Basic", и "Turbo C", и "Turbo Prolog", и "Turbo Pascal"... Ах. "Turbo Assembler", тоже. конечно был. Я не возьмусь сказать, всю ли начальную линейку компиляторов фирмы Борланд я перечислил? Наверняка, нет, простите меня, если чего забыл!.
Для меня, в начале 1990-х стоял выбор, между "Turbo C" и "Turbo Pascal". Си, тогда, в момент начала 1990-х годов проиграл Паскалю мой личный тендер с абсолютно разгромным счётом, почти всухую! Проиграл по той же самой причине. по которой я когда-то ранее отверг Алгол-60: 
просто на Паскале всё было линейно и ясно, а на Си, как и ранее на Алголе, приходилось путаться на ровном месте. Си - слишком краткий (он сознательно таким сделан, чтобы писать максимально полезные программы на компьютерах с минимально доступной памятью). Но из-за этой краткости (и адресной арифметики вкупе с неявными преобразованиями типов) в Си очень легко случайно ошибиться, и очень сложно потом найти свою собственную ошибку (а не дай чёрт, программу писали сразу несколько человек, и тебе лично выпала доля найти ЧУЖУЮ ошибку, вот он, где настоящий АД!!!)

В итоге, Шеркало, как раз к тому времени, как я дорос до настоящего понимания языка Си, и до готовности его всей душой принять, оказалось, что я тогда же из этого языка и вырос. Он стал мне слишком маленьким, неудобным для сколь-нибудь больших приложений, и одновременно слишком тяжеловесным, жёстким для сколь-нибудь реально маленьких приложений. Ни туды, ни сюды. Где такое применить? Ах, да, его в ранних версиях UNIX с успехом применяли... Так и что с этим фактом мне сейчас делать? Да ничего... Остался на Fox и Pascal. Был бы вынужден перейти на Си, если бы работал в коллективе, где это обязательный стандарт, но не пришлось.

четверг, 20 января 2022 г.

Шеркало 05.08: (не)любимые системы программирования (Другие ч.2)

 - ЕР?

- Что такое "ЕР", Ёж, выражайся яснее, пожалуйста!

- "ЕР?" - это общепринятый радиокод такой у радистов-коротковолновиков, сокращение от английского слова "Here?", вопрос "здесь ли ты?", что непонятного, Шеркало?

- А, ясно. Тогда я  -"здесь", продолжай свои байки.


LISP

Ну, тогда в какой бы последовательности продолжить? Начну, наверное, с языка LISP, который по древности лишь совсем немного уступает Фортрану и Алголу. Акроним названия языка расшифровывается, как LISt Processing - обработка списков. Я тот язык, как и Фортран, изучал исключительно "по книжкам", и  исключительно ради научного интереса = из чистого любопытства.

Выглядел LISP изначально примерно вот так:

Я не возьмусь комментировать работоспособность программы с картинки. Тексты на LISP - это реально было ((((ооочень (мнооого) скобочек)))), вызовы функций, вот вся такая красотищща. Изначально меня слегка фрустрировали непонятные имена функций вроде "CAR", "CDR" и "CONS" (на картинке они есть!). Однако, немного позже я узнал, что CAR и CDR - это были мнемоники частей команд языка ассемблера того компьютера, на котором изначально реализовывали LISP. Компьютер тот был IBM 704. Длина машинного слова = 36 бит. Из них 15 бит отводились на значение регистра адреса (Contents of the Address part of Register CAR), а ещё 15 бит на значение регистра декремента (Cotents of the Decrement part of Register CDR). Остальные 6 бит - на код операции или другие признаки. В результате машинное слово IBM 704 делилось (почти) на две адресные половинки (на два полуслова): часть CAR отрезала начальную половинку, игнорируя хвост, часть CDR отрезала хвостовую половинку машинного слова, обнуляя его начало. Ну а команда CONS, как можно догадаться, соединяла два своих коротких "половинчатых" аргумента в одно целое машинное слово компьютера. Получалось, что изначально язык LISP был фактически довольно простой надстройкой над языком ассемблера конкретной компьютерной архитектуры IBM 704, в которой нетрадиционную работу со списками организовали, пользуясь тем, что в одно машинное слово укладывались сразу два адреса ячеек памяти. В результате, CAR указывало на голову списка, CDR - на хвост списка, но этот хвост, в свою очередь, начинался с машинного слова, первая часть которого (CAR) указывала на голову хвоста, а вторая часть слова (CDR) указывала на хвост хвоста... и так до бесконечности очень долго.

Язык LISP в то далёкое время позиционировался, как язык для программирования самого настоящего Искусственного Интеллекта. Я этого, по молодости лет абсолютно не понимал, Ну, какой, в самом деле, может быть "ИскусственныйИнтеллект(tm)" в том, чтобы отрывать в длинных списках невнятных текстов головы от хвостов, потом соединять их в другом порядке помещая головы одних списков в хвосты других списков, а потом решая, какой вариант сочетания голов и хвостов оказался наиболее оптимальным с точки зрения субъективной эрудиции? Что-то в этой схеме не так, верно?!

Позже, со второй попытки, я понял: даже во времена Фортрана и Алгола, не говоря уже о более ранних, компьютеры не могли дать учёным НИЧЕГО, кроме просто очень быстрого вычисления набора математических (по сути арифметических!) ФОРМУЛ. И вот на том фоне примитивного вычисления арифметических выражений, возможность обрабатывать списки (а это автоматически значит - возможность обходить ДЕРЕВЬЯ и произвольные ГРАФЫ решений, с той или иной степенью оптимальности) - это реально в тот момент было интеллектуальным прорывом! Ведь никакой другой язык программирования, на начало 1960-х годов с графами и деревьями оперировать же вообще никак не мог!

Теперь мой личный комментарий, про язык LISP для тебя, Шеркало. Во-первых, я сам на LISP ничего и никогда не писал. Книжку прочитал, да, впечатление получил. Но вот реально работать - не пришлось. Во-вторых, современные диалекты языка LISP (а они есть, язык и сейчас весьма живой, развивающийся!) абсолютно не похожи н картинку из 1960 года, которую я привёл выше. Но, поскольку я ими не пользуюсь, то и писать об этих диалектах я здесь не буду.


Prolog = PROgramming in LOGical

Раз уж заговорили про "ИскусственныйИнтелект(tm)", нужно обязательно упомянуть Prolog. Язык весьма нестандартный. Такие языки называют "декларативными" - есть описание фактов и правил работы с фактами, а там, якобы, сам компьютер логически выведет решение. Гениально? Вот пример простенькой программы на Turbo Prolog 2.0. Специально расшифрую, что там к чему:

Слева - сама декларативная программа.

1. Есть люди, покупатели person() - kelly и judy. Есть товары для продажи for_sale() - pizza,lemon, hot_rod.

2. Есть отношение like(X,Y) - кто из людей, что любит. Есть отношение car(X) - какой товар уже лежит в тележке/корзинке.

3. Есть правило can_buy(), которое говорит, что товары может покупать только известный программе покупатель, только если эти товары есть в списке товаров и уже лежат в тележке (car), но при условии, что покупателю этот товар нравится (like).

В правой части окна пользователь задаёт программе вопросы can_buy, может ли тот или иной покупатель купить тот или иной товар. Соответственно большинство ответов = NO, то покупатель пришёл неизвестный, то товар оказался нелюбимый, то в тележку его не положили. А вот в одном случае всё удачно совпало и can_buy(kelly,hot_rod)=YES - покупка срастается.


Пример конечно чрезмерно примитивный: в данном случае любой идиот школьник решит такую задачу в уме в 100500 раз быстрее, чем программист напишет программу на Прологе. О чём я, кстати, изначально и сам догадывался. Но взрослые умные дяди/тёти мне, школьнику, объясняли, что всё не так просто. 

А дело в том, что с середины 1980-х годов во всей популярной и специальной литературе начались непрекращающиеся экспрессивные крики, буквально лавины восторженных статей, о ВЕЛИКОЙ японской стратегии создания компьютеров аж ПЯТОГО поколения. Японцы, якобы у запада всему-всему за последние годы научились, стали жутко-жутко крутыми компьютерщиками, и теперь весь остальной мир они порвут в интеллектуальном отношении легко, как соседский пёс Тузик тряпичную куклу!!! До меня этот вал про-японской пропаганды, разумеется, доходил большей частью в русскоязычных популяризованных переводах, но умные люди по всему миру, включая известных западных учёных, явно тоже были взволнованы, считали, что нужно срочно "садиться на хвост" японскому прорыву и не отставать, а опережать его! В учебно-программистской среде только о перспективах пятого поколения и говорили, мечтали, что осталось "вот ещё чуть-чуть потерпеть...", а лучше скорее помочь личным участием.

Идеи японского пятого поколения компьютеров были очень просты. Нужно просто взять современный супер-компьютер (или несколько очень мощных мини-микро-рабочих станций, которые все вместе как раз и изобразят такой супер-компьютер), как раз эта часть стратегии пятого поколения на практике тогда вполне реализовалась. Потом научить этот супер-компьютер языку PROLOG, и запихать в него в виде аксиом и правил все-все-все современные знания (как выразить вот прям все-все-все знания в форме аксиом и правил Prolog даже на супер-пупер-компьютере, никто толком не понимал... Но с оговорками... Пусть не все-все-все, а только лишь просто все, но главное - начать!). А в результате, этот супер-компьютер при помощи языка Пролог сам за несколько дней выведет из всех возможных аксиом все возможные в науке теоремы... И... Мы же теперь самые умные сапиенсы во всей вселенной!!! УРА! Ура? Точно ура?

Результат оказался вполне ожидаем. Внезапно (хи-хи, внезапно) выяснилось, что если взять самый супер-пупер-компьютер, напихать в него из всех энциклопедических словарей мильон определений самых умных слов, а потом перемешать с помощью самой умной программы в случайном порядке все эти слова мильон раз самым хитрожопым образом, то всё равно ни разу не получится "Ромео и Джульетта" от Шекспира. И даже простенькая ерунда, вроде "Война и мир" от Толстого, тоже ни разу не получится. Что и было изначально совершенно ясно-понятно не только мне (сопливому ёжику и тогда ещё школьнику), но и всем обычным вменяемым людям тоже. 

Я сейчас утрирую, конечно, сравнивая случайное перемешивание с логическим выводом по правилам. Так делать в общем случае неправильно, но на самом деле аналогия получается очень близкая. Логические выводы из сложного набора аксиом и правил в общем случае и сводятся к простому перебору всех возможных сочетаний применения этих правил к аксиомам. Ну садятся миллион обезьян за миллион калькуляторов, начинают жать на все кнопки подряд. Да, калькуляторы "умнее", чем обезьяны, они будут работать исключительно по правилам арифметики, а на все "лишние" нажатия кнопок будут с умным видом сообщать об ошибке. Вот только толку от подобных "обезьяньих" вычислений всё равно не будет никакого. Почему же вполне вменяемые люди в этом откровенно дебильном цирке всё-таки участвовали? Нет, ну, а как же ещё деньги попилить?! Что, если мы, вроде как будем радеть за научную правду, тогда и все деньги что, тоже - совсем без нас среди других жуликов разделятся? Нет, мы так несогласные!

На быстро и бесславно ушедшем со сцены японском "пятом поколении" компьютеров эта история не закончилась. По нормальной научной инерции, идея надстройки некоего механического (из трёх блатных аккордов основных булевых функций NOT, OR, AND) искусственного интеллекта над некоей абстрактной "базой знаний" (которую никто не знал, как технически реализовать, иначе, чем на Прологе, впрочем и на Прологе тоже никто не знал как), продолжила жить и цвести. Меня в Университете, на третьем, кажись, курсе (это уже начало 1990-х), кафедра пыталась устроить на практику в тот же институт ИОА на тему разработки "Экспертных систем". С точки зрения моих преподавателей в этом не было ничего плохого, они искренне желали студенту (мне) добра, старались дать мне возможность участвовать в "перспективной" современной теме. Они реально не понимали, в чём тут подвох.

Научный руководитель вводил в курс:

- Экспертные системы - это будущее человечества! Представляешь, звонит, например, в поликлинику больной из деревни, говорит: "У меня температура 38, голова болит, и в животе бурлит".

Скорая помощь в ту деревню только на следующие сутки доедет.

Медсестра в поликлинике вводит на компьютере запрос к экспертной системе, смотрит результат на экране.

Экспертная система задаёт доп.вопросы, есть ли сыпь на пятках, с какой-стороны живота сильнее болит, и тому подобное.

В итоге, простая медсестра, при помощи всего лишь персонального компьютера, без вызова вертолёта с врачами в деревню, излечивает больного, вот! Вопросы есть?

- Есть. А если экспертная система по неясным телефонным симптомам ошибётся в диагнозе?

- А она не может ошибаться! Она обучена на 1000 реальных случаев обращений к врачам, каждый из которых провёл не менее 100 успешных диагностик. Значит, она будет выдавать диагнозы не хуже, чем 1000 средних врачей!

- Да, но те врачи имели реальный доступ к больным, могли учесть лёгкие побочные симптомы, какие-то дополнительные, слабоуловимые подсказки, то что не видно на первый взгляд, и что больной постеснялся сказать... Да, и даже 1000 средних врачей, не могут заменить одного квалифицированного специалиста в конкретной области.

- Ерунда! Никаких слабоуловимых подсказок не бывает - мы же материалисты! Анализ на глисты положительный - значит сюда, отрицательный - значит туда. ВСЁ! И никаких дополнительных подсказок! 

А насчёт "1000 не могут заменить одного специалиста"? Ну так у нас мощность компьютеров растёт с каждым годом, память под базу знаний постоянно увеличивается! Будет не 1000 средних врачей, а 1000000 плохих врачей, но количество постепенно само по себе перейдёт в качество, что, студент, Марксистко-Ленинскую философию не изучали в ВУЗе?! 100500миллионов фельдшеров совсем без врачебного опыта, но объединившие свои знания в единой автоматизированной базе, всяко-разно дадут более правильный ответ, чем единственный интеллигент с опытом, но постоянно сомневающийся в своей правоте.

Короче, в теме экспертных систем я не остался и на Прологе больше ничего не писал. И я до сих пор абсолютно не понимаю, не вижу ответа, как можно в общем виде внедрять в компьютерные программы именно знания, а не просто данные. Современный подход - нейронные сети, впечатляет, но задачу решает лишь в узко-ограниченных формах, да и там с периодическими сбоями. Ещё должен добавить, что Пролог также развивается до сих пор (хоть и очень ограниченно). И на нём, в современных версиях, вполне можно писать реальные, достаточно сложные, полезные и интересные программы. Только на других, более распространённых языках, без всякого "логического программирования", те же самые программы обычно пишутся гораздо проще! ;)

Да, Шеркало, в качестве P.S. не могу удержаться, хотел бы добавить о моём личном общении с тем самым "научным руководителем" по экспертным системам. Началось оно с того, что он показал мне моё предполагаемое будущее рабочее место - компьютер IBM PC AT. И с первых минут он стал меня знакомить со знаменитым файловым менеджером "Norton Commander", как с новейшей известной технологией работы.  Если кто не понял, то NortonCommander, он же NC - это те известные "СиниеОкошки", примерно вот такие (картинка утащена из Wikipedia):

И вот, "научный руководитель" по экспертным системам целый день рассказывал и показывал мне, как пользоваться этими окошками, как открывать на разных панельках разные диски или каталоги, и копировать файлы с одной панельки на другую. На второй день, когда выяснилось, что я вспоминаю в NC сочетания клавиш вроде Alt+F1, F5, F7 Alt+F3 и т.п. быстрее, чем он сам, и легко изменяю под свои желания вызываемое по F2 меню, хотя вижу NC второй день в своей жизни (ну не пускали меня раньше на такие "мощные" компы, чтобы одновременно и IBM PC - совместимые, и чтобы NC там был установлен, здесь первый раз увидел), его энтузиазм в отношении меня явно сильно уменьшился, хотя меня это и удивило.

А уж на третий день, когда мы очень откровенно (я по молодости не терпел недомолвок) обсудили моё отношение к ближайшей перспективе внедрения экспертных систем в эксплуатацию... Ну...

В итоге, 

1) меня быстренько, прямо в следующий понедельник, перенаправили на практику в совсем другой отдел ИОА (где, кстати, я успешно прижился, все были взаимно довольны);

2) у меня на всю жизнь осталась любовь к тем самым "СинимОкошечкам", но конечно уже не в варианте NC, время которого ушло вместе с DOS, а в великолепном варианте FAR Manager, которым я продолжаю пользоваться минимум последние 30 лет, и до сих пор ничуть им не разочарован.

вторник, 18 января 2022 г.

Шеркало 05.07: любимые системы программирования (Другие)

 - Шеркало, Шеркало, на окне лежало, под кровать упало,

О порог споткнулось, испугалось, и сразу убежало! Ты где?

- А говорят, что один Ёж как-то раз шёл, шёл, потом споткнулся,

Потом сразу забыл, как дышать. и внезапно задохнулся! Ты как себя чувствуешь?

- Сейчас, кажется, пока ещё нормально. Рассказать тебе чего-нибудь ещё, про любовь?

- Что ты всё про любовь, да про любовь? А вот были у тебя измены твоим любимым языкам?

- Ну ты и вопросы задаёшь! Тема прямо-таки даже на удивление по-людски выглядит. Только языки и стили программирования, это же не любимые люди. Они бесчувственны (хотя и далеко не безличностны!), боли и терзаний не испытывают. Изменять языкам - нормально, и даже, временами, хорошо - сообществом программистов измена одному языку в пользу другого даже часто морально поощряется, называется это: "профессионально-личностный рост". Давай, попробую рассказать.


Начать, наверное нужно с моей измены Паскалю, о котором я говорил в предыдущих двух частях. Дело в том, что уже в первой половине 1990-х годов я вынужден был перейти с учебно-научной работы на более бухгалтерскую, а в середине 90-х и вовсе на чисто банковскую работу. На тот момент Delphi только ещё планировалась к разработке (в прошлом тексте я сознательно забежал чуть вперёд), а чистые IDE Pascal, что в варианте TP/BP для DOS, что в эксклюзивном варианте TPforWindows, для быстрой и успешной реализации офисных-бухгалтерских программ не слишком подходили. Было то самое несоответствие предметной области. Паскаль, он безусловно очень универсален и очень логичен, но для бухгалтерии требуется что-то более готовое к употреблению, что-то более высокоуровневое, с формами, таблицами, отчётами, файлами, базами данных, многопользовательским доступом в одном флаконе.


FoxPro

А вот тут, хочу на минуту отвлечься. Про FoxPro я уже и раньше говорил, и позже чуть ниже ещё скажу. Но FoxPro ведь был не совсем оригинальной системой. Изначально, ещё до эпохи Microsoft, под популярную тогда операционную систему CP/M разработали одну из первых эффективных персональных баз данных dBase II. Позже, с появлением революционного компьютера IBM PC с операционкой MS-DOS, успешную базу данных доработали. Версию популярной уже СУБД под новую систему MS-DOS (она же PC-DOS) выпустила молодая, перспективная фирма Ashton-Tate, её назвали dBase III, чуть позже dBase III+.

В конце 1980-х, начале 90-х, база данных dBase III была абсолютным эталоном СУБД для персональных компьютеров. Конечно же наш продвинутый Университет не мог пропустить мимо своих образовательных программ такое заметное на всемирном уровне приложение. Вот только... среди преподавателей, кажется, не оказалось никого, кто хоть чего-нибудь в этой самой dBase понимал, хотя бы на самом начальном уровне. Там вообще-то (как я понял чуть-чуть позже) не было АБСОЛЮТНО ничего сложного. Стоило лишь мельком, по-диагонали, прочитать прилагаемые readme-файлы. Правда... Правда на английском языке. И вот тут-то большинство наших университетских преподавателей почему-то втихушку заткнулись. Хотя, казалось бы, все образованные люди были? Но ведь всегда проще промолчать, чем взять на себя личную ответственность за перевод для студентов коротенькой примитивной брошюрки на английском языке? Так что dBase III нам упоминали в начале профильного курса... и дальше забывали о нём.

Была и другая, альтернативная ветка преподавания теории СУБД. Именно под неё я и попал. Там вообще не рассматривались БД ориентированные на персональные компьютеры. Настоящие БД могли работать только на огромных мейнфреймах и супер-ЭВМ! Мне долго что-то вдалбливали в мозги про какую-то математически-теоретическую реляционность модели баз данных, про то, что реляционную модель не следует путать с плоским табличным представлением, даже, если оно индексировано, которое является лишь практическим приближением теоретически-идеальной структуры, и требует, как минимум, пяти уровней нормализации, перед тем, как с ним можно будет правильно работать. Правильно написал, не ошибся? Чёрт знает, скорее неправильно. Впрочем, это уже неважно.

Ах да, при этом ещё нужно было помнить разницу между прямыми, косвенными, виртуально-базисными, индексно-последовательными и блочно-распределенными методами доступа (могу ошибаться в конкретных терминах;)), к файловой структуре БД конкретной используемой модели ЕС ЭВМ. Я честно просил преподавателей, показать мне, как это всё на практике работает, хотя бы на примере простейшей БД вида: (школьники Маша, Вася, Петя, изучают Алгебру, Русский, Физику, получают оценки 2,3,4,5). Ведь у нас же ЕСТЬ в университете работающая ЕС ЭВМ!!! Ответ был разочаровывающим: не доросли вы ещё до реализации своих студенческих СУБД на нашей университетской ЕС ЭВМ! Её, болезную, итак непрерывно 100500+ умных инженеров чинят, и починить никак не могут! Она дольше 2-х минут непрерывно работать не может! Так что рисуйте свои СУБД карандашами в тетрадке!

Однако, постепенно ситуация в ИТ-мире менялась. У очень коммерчески успешной СУБД dBase III стали появляться менее лицензионные клоны, некоторые из которых становились очень успешными продуктами. В свою очередь, компьютерные классы университета постепенно стали к началу 1990-х годов наполняться персоналками уровня IBM PC XT (сначала болгарскими Правец-16, а позже и "родными" IBM PS/2). И преподаватели, прежде всего продвинутая молодёжь, понемногу стали обращать внимание в том числе и на персональные СУБД.

Для обучения обычно выбирали самых старательных девочек-отличниц-старшекурсниц. Считалось, что именно они наиболее способны к освоению подобной коммерчески-ориентированной технологии. Я сам ни к категории девочек, ни к категории отличниц разумеется не принадлежал, поэтому начало процесса прошло совсем мимо меня. Однако даже я стал замечать, что некоторые мои однокурсницы на лабораторных работах отсаживаются отдельно и делают что-то своё на таинственно-чёрных экранах, периодически перешёптываясь с аспирантами. Я, из любопытства, попытался узнать, чем они занимаются. В ответ всегда звучали таинственные слова: "Работаем на Клиппере!" Кто такой этот "клиппер" я понять не мог (Интернета-то тогда не было, гуглить было негде!). Но название само по себе звучало очень красиво и романтично. В конце-концов я всё-таки уговорил одну из однокурсниц показать мне ближе свою лабораторную на экране. Увидел я примерно вот это:

- Вот видишь, поясняла однокурсница, - я написала на Клиппере программу: ввожу своё имя Лена, а она меня запоминает в своей базе данных и со мной здоровается. А потом спрашивает, хочу ли я завершить работу. Причём ответ "Yes" специально выделен одним цветом, а ответ "No" - другим, в этой системе даже так можно. И она ждёт какую клавишу я потом нажму, вот!
Я несколько секунд тупо смотрел на экран (кстати, прошу корректность кода программы с картинки оставить на совести той Лены, а ко мне претензии не предъявлять. Я и сам отлично знаю, что эта программа на самом деле работает не совсем так, как её автор заявляет!). 

- Так это же обычный dBase! - констатировал я после недолгой паузы и попытки найти, в чём состоит скрытый подвох.

- Сам ты dBase! - обиделась однокурсница, - это совсем другая система! Это "Клиппер". "CLIPPER", я говорю, слышишь?! Клиппер, в отличии от dBase, позволяет компилировать программы, а не просто набирать их на клавиатуре. Поэтому Клиппер - настоящая профессиональная система! Сейчас на Клиппере весь новый модный софт пишут, и для экономики, и для всяких банков, и для коммерческих фирм! А ты говоришь - dBase...

Так я тогда толком и не понял, что такое "Clipper" и чем он отличается от простого dBase III с подключенными библиотеками run-time исполнения псевдокода. Но некоторый осадочек зависти в душе отложился - вот эта дурочка, которая пять строчек с трёх раз без ошибок написать не может, работает на каком-то модном "профессиональном" Клиппере, а мне вместо этого предлагают какие-то Prolog, Smalltalk и прочие мутные экспертные системы. Может быть это потому, что я - не дурочка?

А потом был у меня другой клон того же dBase III+ - назывался FoxBase. Тоже, как и Clipper, не совсем лицензионный клон (поэтому и более распространённый в СССР, чем оригинал), но очень качественный клон, имеющий к тому же чуть более приятный интерфейс, чем исходный dBase, чуть быстрее работающий. Эпизодически использовал его, когда необходимость в СУБД возникала. Но так... Ничего особо интересного, любить там было нечего. Клон старенькой программы, только и всего. А вот следующая версия FoxBase, которая стала заслуженно называться FoxPro... Вот там уже совершенно другое! Полноценный оконный интерфейс, визуальная среда с конструкторами окон, реально профессиональный доступ к базам данных, в том числе по локальной сети. Это уже была совершенно иная среда исполнения, совершенно другой уровень разработки программ.


FoxPro

Пришлось изменить Паскалю. Я об этом уже писал, система FoxPro 2.x for DOS на тот момент идеально подходила для создания бухгалтерско-офисных приложений. Там было всё желаемое: и формы, и отчёты, и таблицы, и менюшки, и диалоги, и списки, и файлы, и базы данных со всей возможной на тот момент инфраструктурой, и с просто сетевым многопользовательским доступом, и даже с зачатками клиент-серверной архитектуре. И всё это объединено под полнофункциональной IDE/RAD средой быстрой разработки программ (хоть и в псевдографике под DOS).

Повторять (включая картинки) не хочу. Это было. Это было ПОТРЯСАЮЩЕе соитие моих собственных чувств с идеями разработчиков системы! Я не понимаю, почему в эпоху MS DOS FoxPro не стала офисной системой-доминантом?! Причина только лишь в том, что Fox появилась позже, и формально была лишь клоном более ранней dBase? Вероятно так, и это вызывает сожаление.

Однако, факт: она не стала общепринятой. Варианты систем dBase. Clipper, даже Clarion, на мой взгляд все, хотя и были на порядок слабее, чем FoxPro, получали гораздо бОльшую, совсем не заслуженную популярность. Ну, а потом, началась эпоха Windows. FoxPro, купленная к тому времени Microsoft, никаких чудес уже не показывала (Microsoft и не пыталась эту систему развивать, Fox не укладывалась в фирменную линейку продуктов). Пробовал её версию под Windows - ничего реально интересного не увидел  Под DOS, там таки да, там до самого конца 1990-х FoxPro людей впечатляла. Особенно возможностью буквально мгновенно, из буквально дерьма и палок, собрать прямо на коленке действительно вкусную конфетку. Но время DOS прошло, как GUI, так и развивающиеся сетевые технологии потребовали иных парадигм разработки программ. К началу 2000-х FoxPro объективно устарела, причём по нескольким направлениям сразу.


Ассемблер

Наверное, Шеркало, для популярного текста мне нужно рассказать, что такое "ассемблер". Само слово "ассемблер" переводится как "собиратель" и скорее запутывает людей, чем что-то поясняет (просто так исторически сложилось, придётся объяснять). Дело в том, что любой цифровой компьютер на своём компьютерном уровне работает с сигналами (обычно электрическими, но не будем углубляться в ненужные тонкости). У сигналов есть два уровня (условно): единица = есть сигнал, и ноль = нет сигнала. Все команды для компьютера в конечном итоге представляют из себя последовательность сигналов = строчку из нулей и единиц, вроде "0100000000010000010000110110". А компьютер, прочитав эту строчку электрических сигналов, понимает, что ему нужно сделать. Вот эти строчки нулей и единиц, имеющие смысл в рамках системы команд (архитектуры) конкретного компьютера, называются "машинный язык" 

Разумеется, никакой нормальный человек навскидку не может понимать, что эти длинные-предлинные наборы нулей с единицами обозначают. Это только в кино (The Matrix, первая Матрица) один из героев (Сайфер), показывая другому герою фильма (Нео) на ряды непонятных зелёных значков, падающих по экрану компьютера, мог самодовольно говорить: "Я уже даже не вижу код. Я вижу здесь блондинку, брюнетку и рыжую..."

НЕТ! Это у людей так не работает.  Нормальные люди даже после долгих тренировок, воспринимают длинные ряды одинаковых цифр не слишком адекватно. Нормальным людям гораздо понятнее вменяемый алфавитно-цифровой текст. Ну так и в машинном коде каждая 0-1-длинная-цифровая команда разделяется на отдельные смысловые части:

- код операции (ЧТО нужно сделать);

- адреса операндов (откуда брать данные);

- адрес результата (куда сохранить результат выполнения);

- адрес следующей операции (что делать дальше).

Разумеется. не в каждой команде все части нужны одновременно, некоторые или совсем не требуются, или подразумеваются заранее известными по умолчанию. Например, редко требуется адрес следующей команды, часто нужно просто перейти к следующей по порядку операции, а её адрес заранее известен - это +1 относительно выполняемой команды Так же и адрес результата может изначально подразумеваться совпадающим с одним из адресов входных операндов. Но в любом случае, записать (а важнее - прочитать!) машинную команду в "нормальных" буквенных выражениях, структурированную заранее на логические части, это для человека НАМНОГО понятнее. чем. думать, как та же команда запишется нулями и единицами! Там дополнительную прелесть даёт сложная адресация операндов и результатов. Она бывает регистровой (операнд лежит (например) в нулевом регистре компьютера), прямой (операнд лежит в ячейке памяти, указанной явно в команде компьютера), косвенно-регистровой (операнд лежит в ячейке памяти, адрес которой записан в регистре компьютера, который указан в команде), бывает индексной (операнд лежит в ячейке, адрес которой вычисляется, как сумма адресной базы, которая указана в команде явно, и значения индексного регистра, которое умножается на размер элемента дан...

- Ёж, ПРЕКРАТИ!!!

- А... Что? Я что-то не-то сказал?

- Заткнись! Просто заткнись на эту тему! Тебя всё равно никто не слушает.

...

- Понял, извини пожалуйста. Так вот, язык ассемблера, это просто язык, символьный такой язык, на котором машинные команды компьютера записывают в нормальном читабельном виде, словами и цифрами, а не сплошной строкой бит. Но при этом от машинных команд значительно не удаляются - такая вот, условно говоря, запись чисто машинного языка, но вполне человеческими буквами. И обо всех особенностях адресации между кусочками программы тоже заботится транслятор (поэтому и называется "ассемблер" - он собирает единую программу из кусочков-библиотек по разным адресам, взаимно увязывая эти кусочки), человек вручную адреса команд и переменных пересчитывать не обязан. Ещё нужно бы упомянуть понятие макро-ассемблер, но я уже тебя понял, лучше этого не делать.

А вот чего я не могу не подчеркнуть, несмотря на твои предостережения, Шеркало, так это важности использования ассемблера при адресации внутри программы, по сравнению с машинным кодом. Пусть у нас есть простейшая задача:

"Если A>B то выполняем следующую команду, а если нет, то минуя следующую команду, переходим сразу на команду номер 1535". 

Пусть мы это как-то (не важно как, на самом деле не слишком сложно и вручную сделать) самостоятельно написали прямо в машинных кодах. Соответственно и адрес перехода "1535" прямо в машинный код в явном виде забили. А позже вдруг выяснилось, что, если A > B, то нужно выполнить не одну команду, как сначала предполагали, а две, или три, или даже целых 6 команд. Соответственно, переход по условию ИНАЧЕ (A<=B) должен выполняться не на адрес 1535, как ранее задумывали, а на адрес 1536, или на адрес 1540, или вообще на какой-то иной адрес. Ну и вообще, все адреса переходов в программе, которые идут позже нашего упомянутого сравнения A>B, должны быть пересчитаны на совершенно другие ячейки, поскольку размер вышележащей области программы изменился, всё расположение команд по ячейкам сдвинулось. А таких адресов переходов ниже по программе может оказаться много сотен, или даже тысяч. А ещё и ячейки с данными, если они расположены в том же адресном пространстве ниже кода программы (такое не всегда, но бывает), тоже изменят свои адреса. И все места этих переходов и места адресации сместившихся ячеек памяти нужно теперь вручную найти прямо посреди цифрового машинного кода (нужно вычленить команды перехода и адресации, которые меняются, из кучи других команд, которые меняться не должны), пересчитать в них адреса, и вручную их все исправить!

Вот где настоящая собака-то зарыта!!! Только представьте себе, единичное добавление или удаление команды в программе, влечёт за собой сотни или тысячи исправлений в машинном коде этой программы, причём не в каждой команде, а только в выборочных местах! Фактически, при единичном исправлении (добавлении) одного машинного слова, едва ли не всю программу в машинном коде нужно переписывать заново с нуля!!! Каково? Вот! Вот именно для решения ЭТОЙ ситуации с адресацией, а отнюдь не для красивых буквенных мнемоник вместо 0 и 1, и разрабатывали языки Ассемблера. В Ассемблере каждый адрес перехода или адрес ячейки задаётся символической меткой. Конкретное значение этой метке присваивается самим Ассемблером при компиляции программы, программист знать конкретный адрес метки, как правило, совершенно не обязан. Изменили что-то в программе - следовательно фактические значения всех меток в физические адреса внутри машинных команд автоматически пересчитались заново. Автоматически пересчитались все адреса переходов и используемых данных! Вот в этом и есть главная помощь от применения Ассемблера.

Но обязательно требуется упомянуть, что для каждого типа компьютеров (это сейчас называется "архитектурой") языки ассемблера различные. Первым ассемблером, на котором я писал учебные программы был ассемблер IBM/360. Сначала не хотел картинку с ним прикладывать - всё-таки у меня от него почти и не осталось воспоминаний, но потом решил для красоты присобачить вот эту иллюстрацию из учебника 1970 года: 

Тут как раз хорошо виден расчерченный на клеточки типичный IBMовский бланк, отдаваемый операторам для пробивки колоды перфокарт. Точно такие же бланки применялись для ЛЮБЫХ языков на машинах IBM/360, эти же бланки были и для COBOL, и для FORTRAN. Каждая клеточка - один символ большими печатными буквами, каждая строка - один оператор (или команда/псевдокоманда), в строке отдельные поля для меток, операций, операндов и комментария. Я о таких бланках в рассказе про Фортран упоминал, а здесь вот - реальный пример. Хотя сама программа и бессмысленная (точнее исключительно учебно-демонстрационная), но текст весьма похожий на настоящий, он даже откомпилировался бы без ошибок. 

Я с этим ассемблером познакомился на редкой машинке АСВТ М4030 в ИОА (в мой школьный период), которая была совместима по системе машинных команд с IBM/360, хотя к семейству ЕС ЭВМ напрямую и не принадлежала. Никаких интересных программ я на этом ассемблере не писал, в моей памяти ничего не осталось, но после него желание углубляться в программирование резко усилилось - ужасно понравилось!

Вторым моим языком ассемблера был ассемблер PDP-11 (оно же семейство СМ ЭВМ). А вот это уже без всяких скидок была настоящая любовь (третья по счёту?) и измена Паскалю! Правда, измена явно вынужденная. Моими основными домашними компьютерами в студенческий период были БК-0010/0011(М). У этих машин под программы выделялось в общем случае 16 кБ оперативной памяти (точнее даже не 16, а 15.5, и это для домашнего персонального компьютера ОЧЕНЬ МАЛО!). Если хочется (а таки очень даже ДА!) писать собственные программы, то нужно либо довольствоваться Бэйсиком или Фокалом в ПЗУ (и то, и другое - полная лажа), либо использовать ассемблер PDP-11. Компиляторы более-менее нормальных языков высокого уровня (включая обычно предлагаемые "минимально" требовательные Си и PL/M) в таких условиях (там ещё и файловая система для долговременной записи программ и данных на бытовом кассетном магнитофоне с ручным управлением "на слух" изначально была, в сочетании с мизерной оперативной памятью - вообще полная жопа катастрофа) реально задействовать не получалось.

С другой стороны, откат с языков высокого уровня обратно на "низкий" ассемблер в случае с архитектурой PDP-11 ничем "постыдным" не являлся. Большинство людей, которые активно работали с ассемблером PDP-11, позже высказывались примерно в таком духе: "А зачем там вообще нужны эти языки высокого уровня? На PDP-11 и ассемблер ничем не хуже!" Я принадлежу к числу этих людей. Архитектура PDP-11 просто уникальна своей красотой, симметричностью, изяществом. Ни до, ни после ничего подобного не делали (делали конечно, в том числе и прямо по образцу PDP-11 делали, но уже не так здорово получалось). Обычно архитектура компьютера - это ясно видимый мучительный компромисс между техническими особенностями реализации железа и стремлением программистов к собственному удобству. Так вот PDP-11 - это редчайший случай, когда очевидная красота затмевает собой лежащий где-то там глубоко под ней какой-то там несущественный, никому не интересный компромисс с реальностью. Как там А.Миронов/О.Бендер пел? "Замрите ангелы, смотрите - я играю! Моих грехов разбор оставьте до поры, вы оцените красоту игры!"

Выглядело как-то вот так, как сверху, но эта картинка стороннему человеку ничего не скажет. Ассемблер, и есть ассемблер - по одной команде на строку, метки, операции, операнды, комментарии. Всё, вроде бы, как и у остальных. Только окунувшись в такое с головой, начинаешь ощущать скрытую внутри красоту.

На ассемблере PDP-11 (на компьютерах БК-0010/0011(М)) я написал несколько реально используемых прикладных программ, пару курсовых работ, частично свой диплом в Университете. Текст моей дипломной работы я печатал на БК-0011М из текстового редактора собственной разработки, снабжённого драйверами собственной разработки для принтеров Электроника МС6313 и Robotron СМ6329 (компилированных тем же ассемблером PDP-11, разумеется). Очень активное и для своего времени успешное использование языка у меня было, плюс самые тёплые воспоминания о том периоде.


Алгол-68

Очень мало что могу сказать. Язык должен был стать прорывной, прекрасной, впечатляющей весь мир заменой ранним версиям языка Алгол (Алгол-60 и т.п.). На него возлагались очень большие надежды. Все видные учёные-компьютерщики старались привнести в Алгол-68 всё самое лучшее, что успели придумать к тому времени (число 68 в названии языка - это год разработки, если что). В итоге получилось...

Я не знаю, что получилось. Неоднократно мной ранее мной упомянутый гениальный профессор Н.Вирт, который с неизменным энтузиазмом участвовал в разработке и совершенствовании предыдущих версий Алгола, из состава разработчиков языка Алгол-68 выбежал, при этом дико вращая глазами, крутя у своих висков указательными пальцами обеих рук одновременно, и громко хлопая по пути всеми попавшимися под носок ботинка дверями. Однако, поскольку Алгол-68 считался в наших сибирских краях весьма перспективным, я очень хотел его изучить. У меня даже была толстая книжка под названием "Пересмотренное сообщение по языку Алгол-68", в таком жёлтеньком переплёте. И даже с автографом одного из авторов - академика Ершова, вот! Вот только куда она при переездах делась? Шеркало, ты не в курсе?

- Нашёл у кого спросить! Ты ещё к белой берёзе за окошком обратись... Ну, или к ясеню с месяцем, тоже полезно будет.

- Ну, ладно, ладно. Там и без книжки ничего не складывалось. Работающие (скорее всего работающие, кто ж их проверял на серьёзных проектах?) трансляторы Алгола-68 я видел только на больших мэйнфреймах серии ЕС ЭВМ, один раз в ИОА и один раз в Университете ТГУ Ни там, ни там, этот язык никто реально не использовал. Попробовать было негде. Ни любви, ни измены не вышло. Ни одной программы на Алгол-68, даже самой коротенькой, я не написал.

Всё, продолжение в следующем сеансе связи.

суббота, 15 января 2022 г.

Шеркало 05.06: любимые системы программирования (Паскаль ч. 2)

 - Эй, Шеркало, что замолчало? Заснуло что ли?

- Я не заснуло, я только хорька давило! Здоровый такой хорь попался, долго его давить пришлось!

- Ничёсебе! Ты где таких выражений нахваталось, "хорька давить"?!

- Так от тебя же, от кого же ещё?

- Так я ж про того "хорька" уже лет тридцать с лишним не вспоминал!

- Ага, ага... Ты вспомни, Ёж, как буквально сегодня утром вышел погулять на мороз. И кого ты там сразу же у подъезда поймал? А?! Да ещё и не один раз поймал, кажется?

- Нет, прекрати!!! Это ДРУГОЕ! Так интеллигентным людям говорить нельзя! Ты простых человеческих хорьков с нецензурными эфемерными зимними животными не путай, пожалуйста!

- А? Эээ? Ну тогда расскажи, что там у тебя дальше с Паскалем произошло? Ведь наверняка же простого превосходства в прямизне логики над Алголом было мало?

- Да. конечно, я вчерашний день потратил на то, чтобы перечитать статью Кернигана (он один из разработчиков языка Си) "Почему Паскаль - не мой любимый язык (1981)". Ничего особо нового для себя не увидел, хотя читать пришлось на английском - все русские переводы уже забанены, кажется. Но, неважно. Прочитал на английском. И увидел ровно то, о чём читал и раньше, ещё на русском: 

а) есть, немного, реально грамотные претензии (чрезмерная зацикленность Паскаля  на строгой типизации, особенно их видно в границах массивов при передачи параметров функций);

б) есть откровенный бред, из серии "лично мне так было бы удобнее, поэтому я = Д'Артаньян, а все остальные = бяки-буки, по определению" (статические переменные);

в) есть едва ли не единственная оправданная претензия к Паскалю, которая никак не может быть логически обоснована принципами языка, это отсутствие у оператора выбора "Case" варианта "иначе\else\otherwise". Вот реально не понимаю, почему Никлаус Вирт в своё время не включил эту опцию в оператор "Case", и почему упорствовал в её исключении и в дальнейшем? Ведь никаких принципиальных парадигм языка это ничуть не нарушало. И было легко и беспроблемно включено в новые версии языков на базе Паскаля. Что такое принципиальное Вирт здесь защищал?! Не понимаю!

г) множество менее важных недостатков, которые были (почти) общими для абсолютно всех языков высокого уровня своего времени: отсутствие модульности, проблемы с начальной инициализацией памяти, проблемы с организацией ввода/вывода и взаимодействием с внешними устройствами разнообразных компьютеров, и т.п.

е) ничто вышеперечисленное НЕ МОЖЕТ быть исправлено, потому что у языка Паскаль структура вот такая вот кривая = горбатого только могила исправит, а Паскаль изначально учебным пособием сделан. 

Что могу сказать? Почему он тогда так писал, совершенно понятно - всё-таки самолично есть автор альтернативного подхода. Почти все слабости Паскаля, на которые упирал тогда Керниган, были тогда либо уже (именно уже исправлены(!), к моменту выхода его статьи) исправлены, либо находились прямо в процессе исправления. 

- Ну а у меня, Шеркало, тем временем закончилась школа, миновала служба в армии (где о программировании не приходилось даже заикаться), было обучение в Университете, потом (не только потом, но и во время учёбы тоже) началась работа. И пришлось активно заниматься Паскалем. И чем больше на нём писал, тем больше убеждался, что Паскаль - очень гибкий и удобный язык.

Например, в том же ИОА, Паскаль для DEC PDP-11 (СМ ЭВМ, ДВК) транслировал программу не в машинные коды, а в текст на макроассемблере, который потом компилировался уже собственно ассемблером (кстати, не знаю, было ли это обязательной стадией обработки программы, или же только дополнительной опцией, но очень полезно и, кажется, красиво). В результате, в программу высокого уровня можно было совершенно свободно вставлять ассемблерные вставки, в которых, в свою очередь, можно было обращаться к переменным паскалевской программы прямо по их именам. Мечта системного программиста! Примерно вот так:

VAR SIMB :INTEGER;

PROCEDURE TTYIN; 
BEGIN
  (*$C
    NEXT:    EMT   ^O340
                    BCS   NEXT
                    MOV   %0, SIMB(%5)
  *)
END; (* результат машинной команды EMT 340 записывается в переменную SIMB для дальнейшей обработки в Паскале*)

Не знаю, насколько понятным получился пример. Здесь приведена очень простая (но синтаксически правильная) процедура на Паскале, основная часть которой реализована на языке Ассемблера (технически - это как бы комментарий к программе на Паскале, который якобы должен игнорироваться, но на самом деле не игнорируется, а после компиляции передаётся на вход следующему этапу трансляции, макроассемблеру), причём ассемблерная и паскалевская части свободно обмениваются данными друг с другом, имеют доступ к общим переменным, к регистрам, к прерываниям процессора и т.п.. 

Свобода - программистам! Высокоуровневую часть пишу на Паскале, низкоуровневую часть - на ассемблере. Где между ними граница? А нет никакой границы, у нас тут программирование без границ! 

Я мог бы и более интересные и бОльшие по размеру, и по разнообразию низкоуровневых команд, примеры привести. Я сам лично, писал на Паскале программу, обрабатывающую на низком аппаратном уровне (по сути драйвер устройства) команды графопостроителя, рисовавшего графики фломастерами на планшете под управлением одного из компьютеров СМ-ЭВМ-клонов PDP-11. Там как раз основа программы на Паскале писалась, а аппаратные вызовы через регистры ввода/вывода - на ассемблерных вставках. Графопостроитель в ответ на мои команды шустро вытаскивал механической лапкой один из четырёх доступных фломастеров, бегал своей кареткой вдоль и поперёк листа А3, рисовал красивый график по заданному массиву точек, потом возвращал фломастер в своё гнездо  планшета. Вот только, углубляться в дебри архитектуры PDP-11 в контексте языка Паскаль, совсем даже не нужно (как минимум, мне сейчас - не хочется).


- Чуть позже у нас в стране стали повсеместно использоваться "ПК" - Персональные Компьютеры. Многочисленные клоны клонов клонов IBM PC, PC XT, PC AT, PC 386 и далее, и далее, и далее (и до сих пор, если что). Эти машины уже работали не сами по себе, каждая со своими программами. Для их нормального запуска требовалась целая единая для всей серии разношёрстных компьютеров Операционная Система! Все мы помним, какую роль изначально играла MS DOS. Так вот, чтобы писать программы под "самую распространённую" в тот момент операционную систему (MS DOS) компилятор с языка Паскаль уже был!

И он не подводил. Чего ещё можно желать?! Очень изящный, быстрый, удобный, эффективный компилятор. Встроенная среда разработки IDE (Integrated Development Environment) - невероятно удобно, тут же и редактор (да ещё с цветовым выделением синтаксиса), тут же и компилятор, тут же и отладчик, тут же среда тестирования. Речь, разумеется, идёт о знаменитых средах разработки TurboPasal/BorlandPascal.  Это было впечатляющее качество, потрясающая эффективность. Среды разработки от фирмы Борланд временами превосходили конкурентов (в том числе "профессиональные" компиляторы языка Си) по большинству объективных показателей (размер результирующей программы, скорость выполнения программы, скорость компиляции), не говоря уже о субъективных, вроде удобства редактирования текста. Что ты там, Шеркало, говорило про любовь?!

- Я пока молчу, Ёж, я молчу, как морской ёжик в аквариуме с соляной кислотой, продолжай, пожалуйста.

- Не знаю, нужно ли сюда выкладывать картинку с видом среды разработки Borland Pascal 7.0, уж слишком она всем известна? Всё-таки выложу, для полноты повествования:

BP 7.0 был венцом развития Паскаля для операционной системы MS DOS. И это уже был совершенно другой язык, не просто Паскаль от Н.Вирта, а Object Pascal со всеми (почти) преимуществами современной Объектно-ориентированной парадигмы программирования (она сокращается, как "ООП"). Причём внутренне TP/BP остался всё тем же прежним, уютным, изящным и в меру строгим виртовским Паскалем, объектные расширения добавились в язык очень естественным образом, не нарушая сложившийся порядок. Впрочем, подробности парадигмы ООП я здесь расписывать не буду.


А ещё у меня был опыт работы с очень редким Паскалем - Turbo Pascal for Windows. Это такое временное промежуточное звено, когда уже требовалось переходить от DOS к Windows (на тот момент актуальна Windows 3.0), но ничего походящего разработчики придумать ещё не успели. Вот и появился TPfW. Внутри - тот же самый компилятор TP/BP 7.0, но среда разработки переписана с псевдографики на родной интерфейс Windows, и добавлены утилиты для разработки (рисования) частей интерфейса Windows - редактор иконок, дизайнер оконных формочек, генератор ресурсов. Выглядело внешне примерно вот так:

Кстати, самая верхняя функция на той картинке показывает, что работа напрямую с ассемблером никуда не делась, хотя Windows вроде бы и поощряет "высокоуровневое" программирование вместо машинно-зависимого ассемблера. Почему слово "высокоуровневое" я взял в кавычки? А потому что тот самый "высокий" уровень изначально реализовывался через вызовы функций WindowsAPI, которые с точки зрения прикладной программы были максимально низкоуровневыми, ниже просто уже некуда! Вот, для примера, ещё одна картинка с TPfW:

На этой картинке я специально оранжевыми стрелочками выделил сакраментальные функции GetDC/ReleaseDC. О, Шеркало, сколько несчётных раз я вынужден был в своих программах вызывать эту пару функций! Каждый раз, как в очередном окошке Windows требовалось что-то новое вывести (кнопочку "Я - Ёжик" с ёжиком там нарисовать или просто комментарий рамочкой обвести), так нужно было для начала получить Контекст Устройства вывода (Device Context = DC) через функцию GetDC. А закончил рисовать свою кнопочку-рамочку, так изволь тут же немедленно освободить контекст через функцию ReleaseDC. А если ReleaseDC почему-то осталась без вызова, то в следующий раз ты в том же окошке уже ничего не нарисуешь - контекст-то всё ещё занят. И в другом окошке тоже скорее всего ничего не нарисуешь - число свободных контекстов устройств в системе очень сильно ограничено, а кнопочки и закорючки в окошках рисовать не только одна лишь твоя программа желает! И такая вот ерундень повторялась сквозь весь WindowsAPI - хочешь что-то вывести/убрать/передвинуть в окошках, пиши целые листы вызовов функций с маловразумительными списками параметров, плюс функции отлавливания CallBak'ов, которые должны вернуть тебе управление в исключительных ситуациях, и внимательно следи, чтобы они вызывались строго в нужном порядке, несмотря на общую нелинейную схему вызовов с прерываниями по инициативе пользователя.


Честно, если бы Паскаль остановился на уровне TPforWindows с его "чистым" незамутнённым WindowsAPI, вряд ли этот язык остался бы в списке моих любимых. Но разработчики фирмы Борланд сравнительно оперативно предложили новую интегрированную среду разработки (IDE, а так же средство Rapid Application Development = RAD) под названием Delphi, мгновенно ставшую знаменитой. Не то, чтобы Delphi была самой первой IDE/RAD, нет, были интересные системы и раньше, в том числе и под Windows (хотя именно под Windows до Delphi реально было очень мало адекватных сред разработки). Но по совокупности свойств Delphi стала прорывом и образцом для подражаний. Картинку попробую приложить, чтобы два раза не вставать, хотя вряд ли кто-то не видел подобных картинок:

Вот тут реально все возможные прелести собраны в одну кучу! Доведённый почти до совершенства язык Object Pascal (в каком далёком прошлом остались претензии Кернигана к бесполезному "учебному" языку, на котором ничего работающего написать невозможно?!). Нормальная разработка программ под Windows - все ужасы WindowsAPI полностью скрыты "под капотом", а наружу выставлена довольно разумная, и уж точно высокоуровневая библиотека Visual Component Library = VCL. Разработка программы на базе готовых компонентов в рамках модели ООП. Встроенная разработка форм с полноценным интерфейсом Windows, готовый доступ к базам данных, удобный доступ ко многим системным ресурсам... 


- Достаточно, Шеркало? Может быть хватит на сегодня? Может мне тоже пойти, хорька подавить?

- Кажется давно пора.