Logo

29 декабря 2013 г.

Отказ от встроенных типов и булевый тип

Объявленный ранее отказ от встроенных типов оказывает большое влияние на булевый тип —единственный конечный тип, значения которого не имеют естественного представления. В других языках программирования значения «ложь» и «истина» обозначаются либо константами, либо ключевыми словами. Как поступить в Канторе?

Ранее, вместе со встроенными типами в Канторе были зарезервированы ключевые слова false и true, упрощавшие, как казалось, вывод типов при объявлении функций. Отказ от встроенных типов заставляет принять решение — либо признать булевский тип исключительным и оставить ключевые слова, либо изъять ключевые слова в пользу констант. Не усложнит ли это объявление булевых функций?

Константы и пространства имен

Основная сложность перехода на булевы константы — размещение класса Boolean в пространстве :Core. Это логично, поскольку булевый тип — один из базовых. Но из других пространств ссылки на константы будут иметь комплексный вид — :Core:Boolean.False и :Core:Boolean.True. На первый взгляд смотрится неудобно, но даже самый простой пример вносит ясность:
:Core:Boolean a = False;
Локальная функция a имеет тип :Core:Boolean, что заставляет компилятор искать объявление False в пространстве класса :Core:Boolean, объявление которого выглядит так:
public final class :Core:Boolean = [False, True];
Данное объявление подразумевает, что свойство False объявлено как статическое (концепция перечислений пока в разработке), поэтому объявление функции a валидно, и она успешно скомпилируется.

Поиск имени в пространстве класса — базовое соглашение видимости имен в Канторе, сильно упрощающее использование перечислимых типов, в том числе Boolean:

Альтернативные способы

Если базовый способ объявления булевых значений по каким-то причинам не подходит, есть как минимум два альтернативных способа — при помощи выражения или же обращением к свойству AsBoolean:
a = 0 == 1;      // выражением, как в SQL
b = 0.AsBoolean; // через свойство
Сравнение констант, дающее предопределенный результат, долгое время было распространено в СУБД, поскольку не влияло на выдачу, но задействовало оптимизатор.

Свойство AsBoolean должно быть реализовано классом, как уже сделано в классе :Core:Word — тип выведен из значения 0.

Практика использования булевых констант

Так ли часто придется явно использовать булевы константы на практике? Видятся следующие случаи:
  • Если при объявлении параметра или свойства задать тип, константа становится видна по короткому имени.
  • Параметры и свойства, имеющие значения по умолчанию, чаще всего опускаются при обращении, если значение по умолчанию подобрано верно.
  • Если булевы свойства и параметры не имеют значений по умолчанию, либо умолчания нужно перекрыть, в точке обращения тип свойства или параметра уже известен компилятору, и к соответствующей константе можно обращаться по короткому имени. Тут действует то же соглашение, что и в первом рассмотренном примере.
Единственная сложность, которая может возникнуть — обращение к перегруженному свойству с булевыми параметрами в перегруженной части. Это относится не только к булевому, но и к любому другому перечислимому типу. При пересечении имен свойств в классах перегруженных параметров возникнет коллизия, и при обращении к свойству придется указывать полное имя константы. Поскольку коллизии возникают при неправильной декомпозиции, это может стать поводом для рефакторинга и нормализации классов.

Текущее состояние

Исходя из перечисленных соглашений и случаев использования, ключевые слова false и true планируется исключить из синтаксиса, приравняв булевый тип к другим перечислимым типам. Для принятия окончательного решения требуется также проработать представление перечислимых типов в ядре (в данной статье оно дано схематично).

28 декабря 2013 г.

Цикл с параметром как итератор

Представленные ранее циклы «пока» и «до» — чисто алгоритмические конструкции, их описание не вызвало затруднений. В отношении цикла с параметром, напротив, высказана гипотеза, что данный цикл является не просто итератором, но алгоритмической формой запроса, по смыслу аналогичного оператору SQL select. В настоящий момент концепция прорабатывается, поэтому статья носит предварительный характер.

На момент написания статьи принято, что оператор for в декларативном синтаксисе может являться аналогом оператора select в командном синтаксисе, при условии, что оператор select также имеется в языке Кантор.

Итератор вместо счетчика

В практическом программировании цикл с параметром чаще всего используется для обхода контейнеров — в качестве итератора. Язык Кантор ориентирован на контейнеры, поэтому для цикла с параметром форма итератора принята в качестве основной. Синтаксис for в Канторе близок к for из PL/SQL и больше похож на foreach в некоторых языках программирования, нежели на традиционный for со счетчиком. Простой счетчик, если потребуется, будет представлен как виртуальный (пустой) контейнер, не содержащий ничего, кроме индексов.

Опора на итератор однозначно решает вопрос видимости внутренней переменной цикла, соответствующей текущему элементу: объявление переменной в Канторе является частью оператора цикла, а сама переменная — локальным именем внутри него, снаружи она не видна.

Простой перебор

Как уже говорилось, цикл for в Канторе восходит к PL/SQL:
for элемент in контейнер do
  ветвь;
end;
Внутренняя переменная элемент имеет тип элемента контейнера — выводится компилятором. Поддержка итераций реализуется контейнером через множественное наследование, как конкретно — будет проработано в дальнейшем.

Перебор нескольких контейнеров

Один из архитектурных принципов языка Кантор — множественность шагов цикла, что уже позволило реализовать цикл Дейкстры и цикл «паук». Применение принципа к циклу с параметром вполне логично ведет к возможности перебора нескольких контейнеров одним оператором, примерно так:
for элемент1 in контейнер1, элемент2 in контейнер2, элемент3 in контейнер3 do
  ветвь;
end;
Сложность в том, что в арифметике контейнеров такая запись соответствует декартову произведению и на практике требуется довольно редко. Кроме того, контейнеры в Канторе имеют собственные итераторы — inner и outer — для обхода деревьев и графов соответственно. Выражения контейнерной арифметики могут также содержать блоки условий where и агрегатных функций. С этой точки зрения декартово произведение в for выглядит весьма спорно, поэтому данная конструкция пока не утверждена.

Стои́т также вопрос, останется ли вообще оператор select, принятый в Канторе на ранних этапах, в виде самостоятельного оператора, или же ключевое слово select уйдет из языка, уступив место обычным выражениям в простых случаях и блокам with, в том числе with с for — в сложных? На этот вопрос пока нет однозначного ответа, понятно лишь, что имеется тесная взаимосвязь select, for и контейнерной арифметики. Решение по ним будет приниматься комплексно.

27 декабря 2013 г.

Отказ от встроенных типов

Ранее считалось, что в языке Кантор есть встроенные типы, обозначаемые ключевыми словами int, word, float, bool, byte, char, string, text и wiki. Компромисс основывался на допущении, что встроенных типов будет достаточно для общих случаев, особенно при наличии развитого вывода типов.

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

Можно ли обойтись встроенными типами?

Как говорилось, встроенные типы предназначались для неких общих и простых случаев. Высказывалось предположение, что такие случаи бывают, и возможностей встроенных типов окажется достаточно для их покрытия. Допущение было чисто умозрительным, поскольку на ранних этапах еще не было примеров кода на Канторе, а у его автора не было опыта программирования на нем. Позже, когда примеры появились, вместе с опытом пришло понимание, что «общие» и «простые» случаи весьма затруднительно отделить от всех остальных, что делает аргумент о надобности встроенных типов негодным, а выбор конкретных типов из множества — волюнтаристским. В самом деле, почему именно эти типы делать встроенными?

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

Неоднородность синтаксиса

Мысль об отказе от встроенных типов возникла из-за видимой глазом неоднородности синтаксиса в примерах: встроенные типы обозначаются ключевым словом, а остальные — обычным идентификатором. Сравните два описания:
var of
  int IntValue1 = 0;
  Integer IntValue2 = 0;
end;
IntValue1 и IntValue2 — целые переменные, а объявлены по-разному. Никакого скрытого смысла здесь нет, просто так захотелось программисту. Если язык допускает подобную самодеятельность, — это плохой язык.

Как обойтись без встроенных типов?

Язык Кантор — чисто объектно-ориентированный, то есть все типы в нем являются классами. Это означает, что имеется только один встроенный тип — class, функциональность которого обеспечивается компилятором. Данная концепция — прямая и однозначная реализация как понятия чистого ОО-языка, так и принятого в Канторе архитектурного подхода, что ключевыми словами обозначаются только те понятия, которые могут быть реализованы только магией компилятора и никак иначе.

Поскольку Кантор изначально проектировался как язык, синтаксис которого реализуется RTL, вывод типов в нем привязывался к предопределенным классам RTL. Затем часть предопределенных классов обозначалась ключевыми словами, что и давало встроенные типы. Предполагалось, что при компиляции ключевые слова будут развертываться в классы, поскольку в байт-коде могут храниться только ссылки на классы, а ключевые слова — синтаксическое понятие. Отказ от встроенных типов лишь избавит компилятор и отекстовщик от работы по развертыванию ключевых слов в классы RTL и наоборот, не затрагивая остальных концепций.

Межпространственная адресация

Очень редко отказ от чего-либо проходит полностью безболезненно. Отказ от встроенных типов в Канторе требует решения другой проблемы — упрощения ссылок на классы из другого пространства. Проще пояснить это на примере:
public class Model of
  public class CantorSys of
    public class HelloWorld of
      public out :Core:String Hello;
    end;
  end;
end;
Фрактал, в котором работает Кантор, делится на пространства — корневые контейнеры, инкапсулирующие среды с разным временем жизни объектов и способом доступа к ним, играющие также роль пространства имен. Корень всех пространств обозначается двоеточием, вложенные объекты в пространствах также разделяются двоеточием.

В примере выше корневые пространства :Model и :Core являются классами, а описание свойства :Model:CantorSys:HelloWorld.Hello ссылается на класс :Core:String. Во фрактальной среде вложенных описаний не избежать никак, и даже в простом примере они уже не такие короткие. На будущее нужно продумать механизм, упрощающий межпространственную адресацию, делающий это очевидным способом и однозначно ложащийся в байт-код.

5 декабря 2013 г.

Цикл «до» и цикл «паук»

Раз цикл Дейкстры — многоуровневая форма цикла «пока», должен существовать его зеркальный аналог в форме цикла «до» с несколькими ветвями. В литературе он известен как цикл «паук».

При разработке языка Кантор оператор многоуровневого «до» был выведен эмпирически, а его описание и сам термин «паук» найдены позже. На момент написания статьи Википедия утверждает, что цикл «паук» ни в одном языке программирования пока не реализован, поэтому Кантор вполне может стать первым языком с циклом «паук».

В языке Кантор пока принято, что циклы имеются только в декларативном синтаксисе.

Цикл «до»

В форме с одной ветвью оператор repeat имеет вид обычного цикла «до»:
repeat
  ветвь;
until условие;
Цикл repeat — блочный оператор, поэтому операторы его ветвей разделяются точкой с запятой. Краткая форма repeat в Канторе — единственный блочный оператор, не оканчивающийся обязательным end.

Вырождение цикла «до» в бесконечный цикл

Использование цикла «до» в реальном программировании требует выполнения завершающих действий перед выходом — эпилога. Цикл «до» при этом вырождается в бесконечный, требуя дополнительных механизмов выхода из него. Традиционное решение — оператор досрочного выхода.

О вырождении цикла «до» в бесконечный наверняка знали разработчики языка PL/SQL. В PL/SQL цикл «до» отсутствует вовсе, зато имеется бесконечный do loop и оператор досрочного выхода exit when, который пишется столько раз, сколько разных условий (ветвей) выхода имеется.

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

Цикл «до» с эпилогом

Введение эпилога — первый шаг по адаптации цикла «до» к форме, не требующей оператора досрочного выхода. Цикл «до» с эпилогом имеет в Канторе следующий вид:
repeat
  ветвь;
until условие then
  эпилог;
end;
В этой форме после условия выхода until пишется ключевое слово then, за которым идут операторы эпилога, разделенные точкой с запятой. В конце эпилога ставится обязательный end.

Цикл «паук»

Оператор repeat с эпилогом легко расширяем до формы с несколькими ветвями. Дополнительные ветви начинаются ключевым словом else и оканчиваются собственным until и условием выхода, после которого также идет эпилог:
repeat
  ветвь;
until условие then
  эпилог;
else
  ветвь;
until условие then
  эпилог;
else
  ветвь;
until условие then
  эпилог;
end;
Полная форма оператора repeat не позволяет пропустить эпилог какой-либо ветви, кроме последней. В рамках проекта высказана гипотеза, что принятая в Канторе запись является естественной для цикла «паук», и надобности в пропуске эпилогов промежуточных ветвей не возникнет. В будущем гипотеза будет проверена на практике.

После исключения циклов из синтаксиса ключевые слова repeat и until больше не подсвечиваются.

28 ноября 2013 г.

Цикл «пока» и цикл Дейкстры

Развитие оператора цикла while до варианта с несколькими ветвями дает цикл Дейкстры, введенный в язык Кантор под влиянием Оберона-07.

На момент написания статьи принято, что операторы цикла имеются только в декларативном синтаксисе.

Цикл «пока»

В варианте с одной ветвью цикл Дейкстры имеет форму обычного цикла «пока»:
while условие do
  ветвь;
end;
Единственная ветвь цикла выполняется, пока условие истинно. Цикл — блочный оператор, поэтому операторы ветви разделяются точкой с запятой, и завершающий end обязателен.

Цикл Дейкстры

В полной форме оператор цикла «пока» становится циклом Дейкстры. Его особенность в языке Кантор — наличие эпилога:
while условие do
  ветвь;
elsif условие do
  ветвь;
elsif условие do
  ветвь;
else
  эпилог;
end;
Логика цикла:
  • На каждой итерации:
    • Последовательно вычисляются условия while и elsif.
    • При истинности условия соответствующая ветвь выполняется — одна ветвь на каждой итерации.
  • Если выполнена хоть одна итерация, перед выходом из цикла выполняется эпилог.
На момент написания статьи предполагается, что введение полноценного цикла Дейкстры и концепции эпилога избавляет от надобности в операторах досрочного выхода и продолжения цикла — break и continue. Эти операторы в языке Кантор отсутствуют.

После исключения циклов и elsif из синтаксиса ключевые слова while и elsif больше не подсвечиваются.

Ветвление и выбор

В языке Кантор учитывается не только опыт Паскаля и Си, но и Ады с PL/SQL, что влияет на синтаксис. Влияние заметно в операторах if и case.

В этой статье рассматривается только декларативный синтаксис.

Оператор ветвления

Принятый в Канторе оператор ветвления считается уже классическим:
if условие then
  ветвь;
elsif условие then
  ветвь;
elsif условие then
  ветвь;
else
  ветвь;
end;
Ветви elsif и else могут отсутствовать, завершающий end обязателен.

Оператор if может использоваться в форме выражения — тогда вместо ветвей стоят одиночные выражения или кортежи, соответствующие возвращаемым значениям, а точка с запятой внутри ветвей не ставится:
a, b = if условие then
  выражение_a, выражение_b
elsif условие then
  выражение_a, выражение_b
elsif условие then
  выражение_a, выражение_b
else
  выражение_a, выражение_b
end;
В таком виде оператор if ближе всего к case when из SQL.

После исключения elsif из синтаксиса ключевое слово elsif в коде больше не подсвечивается.

Оператор выбора

Отличительная особенность оператора case в Канторе — наличие пролога:
case выражение1, выражение2 of
  пролог;
when значение1, значение2 then
  ветвь;
when значение1, значение2 then
  ветвь;
else
  ветвь;
end;
Условием выбора может быть кортеж, то есть несколько выражений, как ключ в БД. Работает оператор следующим образом:
  • Выражения case вычисляются один раз.
  • Если значения совпадают с одним из when, выполняется пролог и эта ветвь.
  • Если значения ни с одним when не совпадают, выполняется только блок else, без пролога.
Наличие хотя бы одного when обязательно, иначе оператор вырождается if без условия, чего быть не может. Блок else может отсутствовать, завершающий end обязателен.

Имеется и выражение case:
a, b = case выражение1, выражение2, выражение3 [of]
  when значение1, значение2, значение3 then
    значение_a, значение_b
  when значение1, значение2, значение3 then
    значение_a, значение_b
else
  значение_a, значение_b
end;
В выражении case пролог отсутствует, поэтому of не обязателен. Точка с запятой внутри ветвей также не ставится. Из-за поддержки кортежей выражением case удобно расписывать таблицы трансляции или подстановки значений.

Ключевые слова when и then введены в case ради кортежей и единообразия: ветви сложных операторов должны начинаться ключевым словом, иначе и синтаксис неоднозначен, и глазу не за что зацепиться. Двоеточие зарезервировано в языке для других целей.

Выражение как строчный оператор

Выражения if и case относятся к разновидности строчных операторов в терминах языка Кантор, обладая следующими признаками:
  • Содержат в ветвях только выражения или кортежи, поэтому могут встраиваться в другие выражения и кортежи подходящего типа.
  • Не имеют побочных эффектов — являются чистыми.
  • Не содержат внутри себя разделителя «точка с запятой» — общий признак всех строчных операторов. 

Фрактальная модель: важность наследования

Поиск определения объектно-ориентированной ОС велся путем последовательного применения понятий ООП к классическим ОС и исключением понятий из рассмотрения при обнаружении применимости.

Инкапсуляция

Инкапсуляция — это сокрытие данных и/или реализации, вне ООП известно как принцип «черного ящика». В классических ОС инкапсуляция прямо или косвенно используется в понятиях файла и программы:
  • ОС контролирует только имя и атрибуты файла, но его содержимое как прикладную сущность.
  • Подход к программе как к «черному ящику» вынуждает вводить защиту (кольца защиты, страничную защиту), без которых ОС считается потенциально уязвимой.
Существование вне ООП и присутствие в классических ОС исключает инкапсуляцию из рассмотрения.

Полиморфизм

Под полиморфизмом понимают частную реализацию абстрактного интерфейса, позволяющую выполнять заданные интерфейсом действия общим способом, не заботясь или не зная об особенностях ее реализации. Вырожденным случаем полиморфизма в классических ОС можно считать саму концепцию программ.

Каждая программа является реализацией абстрактного интерфейса, описываемым на языке Кантор как:
public class Program of
  public out Integer Execute(String Args[Word]);
end;
В тех ОС, где получение входных параметров требует вызова функции API, интерфейс еще проще:
public class Program of
  public out Integer Execute;
end;
В классических ОС интерфейс всего один, поэтому полиморфизм считается вырожденным. Реализация интерфейса программами — первый случай полиморфизма.

Если формат исполняемого файла позволяет хранить код для нескольких сред или поколений ОС, возможен второй случай — полиморфное поведение. Примером служит утилита bootpart, исполняемый файл которой работает как в DOS, так и в Windows, в каждом случае используя API именно той ОС, из-под которой она была запущена.

Наверняка есть и другие случаи полиморфизма вне ООП, ускользнувшие от внимания автора. Для анализа важно лишь существование такого полиморфизма, что исключает полиморфизм из дальнейшего рассмотрения.

Наследование

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

Примеров наследования вне объектно-ориентированного программирования или в классических ОС не найдено. Существуют противоположные примеры — системы и среды с реализацией подмножества ООП, где наследование ограничено интерфейсами и/или заменено другим суррогатом. Эти системы мы условились называть «ОС с объектами», также их называют объектными — в противоположность полноценным объектно-ориентированным системам, реализующим наследование.

Отсутствие наследования вне ООП и (косвенно) сложность реализации на системном уровне дали основание считать его ключевой особенностью объектно-ориентированной ОС. Как уже говорилось, в проекте принято, что объектно-ориентированная ОС порождает программы наследованием.

Ссылки

27 ноября 2013 г.

Фрактальная модель: объектно-ориентированная ОС

Приступая к разработке любого проекта, важно дать ему определение. Данный проект — объектно-ориентированная ОС. Попытки найти существующее определение объектно-ориентированной ОС ни к чему не привели, что дает основание полагать, что такое определение попросту отсутствует.

ООП и системное программирование

В 90-х годах XX века вместе с распространением графического интерфейса и ОС Windows объектно-ориентированное программирование набрало популярность и быстро стало массовым. В ИТ-журналах той поры стали появляться статьи, предсказывающие скорое появление объектно-ориентированной ОС, попутно пытаясь дать ей определение. Ссылки на некоторые публикации перечислены в конце статьи. Вероятно, за частью статей стояли научные исследования, поскольку публиковались они от имени известных деятелей компьютерной индустрии, а журнал «Открытые системы» даже имеет аккредитацию ВАК.

Чтение статей подталкивает к выводу, что в системном программировании ООП либо нет вовсе, либо имеется какое-то свое, особое ООП, поскольку оно рассматривается в отрыве от ОС или увязывается с микроядром, а не инкапсуляцией, полиморфизмом и наследованием, как следовало бы ожидать:
Микроядро с четко очерченным минимальным набором интерфейсов обеспечивает фундамент для построения модульной операционной системы. Однако вместе с этим требуется применение некоторого дисциплинирующего подхода, организующего процесс модульных расширений микроядра. На сегодняшний день наиболее популярен объектно-ориентированный подход, который также находит надежную опору в микроядерной технологии, а точнее, во встроенном и оптимизированном механизме передачи сообщений.
Можно предположить, что из похожих статей в авторитетных источниках определение объектно-ориентированной ОС проникло в «Финансовый словарь», формулировку из которого поисковики выдают на первом месте:
Объектно-ориентированная операционная система — операционная система, имеющая объектно-ориентированную архитектуру. Основные функции объектно-ориентированной ОС реализует микроядро, над которым располагаются сервисные модули. С микроядром связаны объектно-ориентированные языки программирования. Ресурсы объектно-ориентированной ОС используют прикладные программы.
Определение не является ни формальным, ни инженерным. На это косвенно указывает его присутствие только в непрофильном словаре. В толковых словарях для программистов вообще никакого определения объектно-ориентированной ОС нет.

Объектно-ориентированная ОС

В проекте принято определение объектно-ориентированной ОС с опорой на понятия ООП:
Объектно-ориентированная ОС порождает программы наследованием.

Определение выведено эмпирически. Рассуждения, как оно появилось, вынесены в отдельную статью.

Ключевая особенность системы, построенной на наследовании, хорошо иллюстрируется цитатой из книги «Сетевые операционные системы»:
Для обеспечения преемственности при переходе к более детальному описанию разработчикам предлагается механизм наследования свойств уже существующих объектов, то есть механизм, позволяющий порождать более конкретные объекты из более общих. Например, при наличии объекта «текстовый документ» разработчик может легко создать объект «текстовый документ в формате Word 6.0», добавив соответствующее свойство к базовому объекту. Механизм наследования позволяет создать иерархию объектов, в которой каждый объект более низкого уровня приобретает все свойства своего предка.
Наследование применимо и к программам. Разработчик может унаследовать класс Notepad, добавить нужную функциональность и получить WordPad; снова унаследовать и довести возможности нового класса-программы до уровня Word.

Задачи ядра ОС

Работа ООП на системном уровне обеспечивается поддержкой со стороны ядра ОС.
Помимо задач, характерных для ядра обычной ОС, ядро объектно-ориентированной ОС должно поддерживать программную среду с контролем целостности наследования, полиморфизма и агрегации.
Эта особенность сближает ядро ОС с ядром СУБД, выполняющим сходные задачи, но в рамках реляционной модели. На примере ранних, нереляционных СУБД видно, что без контроля целостности построение надежной и гибкой системы затруднено или вовсе невозможно.

Схожесть с СУБД признана основополагающей. В проекте считается, что объектно-ориентированная ОС и объектно-ориентированная СУБД — одно и то же. Объектно-ориентированная ОС будет иметь функциональность СУБД, и наоборот, объектно-ориентированная СУБД будет иметь функциональность ОС.

ОС с объектами

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

ОС, система, среда

Хоть предмет разработок и обозначен понятием «ОС», это не обязательно: его можно заменить словом «система» или «среда», — смысл написанного не изменится.

Ссылки

Строчные и блочные объявления

Операторы в языке Кантор могут иметь строчную или блочную запись. В строчной форме записываются простые выражения и кортежи, а в блочной — все остальные операторы. Вне зависимости от формы записи операторы разделяются точкой с запятой.

В этой статье рассматривается только декларативный синтаксис.

Выражения и кортежи

Во многих случаях строчная форма является естественной для выражений и кортежей. Чаще всего это описания простых функций, в том числе переменных, рассматриваемых в языке Кантор как функции:
a = 5;                     // простая функция
[c, d] = [100, 'пятьсот']; // кортеж
plus2[int val] = val + 2;  // с параметром

var s = 'строка', x = 100; // кортеж инициализированных переменных
Строка в строчной записи — понятие условное. Строчный оператор может занимать сколько угодно строк исходного текста, завершаясь точкой с запятой. Несколько объявлений, разделенных запятой, превращают оператор в кортеж (в терминах языка Кантор). Объявление параметров функций — особый вид кортежа, он будет рассмотрен отдельно.

Блочные объявления

Бывает так, что идущие друг за другом объявления образуют логический блок, который хотелось бы выделить синтаксически, но строчная запись, наоборот, только усложняет восприятие, вытягивая описание в строку и делая его невыразительным. Если оператор разбить на строки и в строчном синтаксисе, отдельные объявления будут завершаться запятой, а последнее объявление — точкой с запятой, что нелогично:
var Byte HeaderVersion = 1;
var Word[32] ImageStart = 16, ImageEnd = 768,
  MemSize = 8192, StackSize = 4096,
  ParamCount = 0;
var HasIcon = false;
Для таких случаев в Канторе предусмотрена блочная форма объявления, объединяющая функции одного типа и/или с одним набором модификаторов в блок of..end, внутри которого отдельные объявления единообразно разделяются точкой с запятой:
var of
  Byte HeaderVersion = 1;
  Word[32] of
    ImageStart = 16;
    ImageEnd = 768;
    MemSize = 8192;
    StackSize = 4096;
    ParamCount = 0;
  end;
  HasIcon = false;
end;
Блоки могут произвольно вкладываться друг в друга, модификаторы при этом суммируются, а взаимоисключающие — перекрываются (еще не решено окончательно).

Несмотря на разность записи, в обоих случаях объявляется несколько самостоятельных функций-переменных, не объединенных ни в какую структуру: HeaderVersion, ImageStart, ImageEnd, MemSize, StackSize, ParamCount, HasIcon.

Запланировано, что на уровне байт-кода оба описания будут абсолютно идентичны, и при отекстовке байт-кода можно будет выбрать предпочитаемую форму — строчную или блочную.

Блоки локальных функций

Другой случай, когда полезен блок объявлений — ограничение видимости локальных имен. Для этого служит оператор-префикс with. Он может предшествовать любому блочному оператору, ограничивая область видимости объявленных в нем имен только этим оператором. С ключевым словом do блок with можно использовать и со строчными объявлениями:
a = 50;
with
  a = 2;
  b = 20;
do
  rslt = a * b;  // = 40
end;
В данном примере на внешнем уровне видны только две функции-константы: a, равная 50, и rslt, равная 40.

Блоки with также могут вкладываться друг в друга.

Синтаксис блочных операторов

Блочные операторы могут быть «многоэтажными», при этом каждая часть имеет блочную запись с разделением вложенных операторов точкой с запятой. Завершается блочный оператор ключевым словом end, после которого ставится точка с запятой — разделитель операторов.

22 ноября 2013 г.

11-я линия В. О., 24

Анонсированный памятник Стиву Джобсу на Embedded Meetup нам так не показали, а вот я до начала меропрятия прошелся до 11-й линии, где в доме №24 жил будущий немецкий математик Георг Кантор.

20 ноября 2013 г.

Тезисы к семинару на Embedded Meetup #2: Связь ООП и ФП

Статьи по теме

Развитие ПО отстает от железа

  • Развитие ПО экстенсивно, требует много рутинного труда.
  • Потеря бинарной совместимости из-за распространения скриптовых языков и платформ JVM и .NET.
  • При этом всё системное и системообразующее ПО написано на одном языке (и в одной стране).
  • Пример: большие накладные расходы WebSVN.

ООП, ФП и СУБД

  • Классы — это функции от состояния , объекты — само состояние.
  • Переменная (объект) — функция, имеющая реализацию памятью.
  • Свойство — функция, имеющая реализацию либо кодом, либо памятью, либо и кодом, и памятью.
  • Всё это похоже на СУБД:
    • Представление → функция.
    • Таблица → объект → переменная.
    • Материализованное представление → представление и таблица одновременно → свойство.

Тезисы к семинару на Embedded Meetup #2

Вводная

Бизнес-план Гордона Мура изменил направление и теперь по-другому влияет на развитие технологий. На одном из выступлений докладчик Intel назвал закон Мура бизнес-планом Мура, а потом продемонстрировал график, на котором монотонный рост вычислительной мощности преломляется в момент появления первого двухъядерного процессора, после чего фактическое увеличение быстродействия ПО отстает от номинальной производительности процессоров: программы не могут использовать возможности железа, график делится надвое.

Кроме того, есть множество технологий, появившихся еще в 70-е годы XX века, но так и не нашедших воплощения на системном уровне. Было много попыток разработать объектно-ориентированную ОС, но все они так и остались в лабораториях. Почему? Неужели по-прежнему не хватает вычислительной мощности? А кто помнит слова Алана Кея: "Создавая ООП, я не имел в виду C++"?

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

Что предлагаю я: массовое функциональное программирование

Разработка на императивных языках программирования должна была начать умирать еще заранее, до появления первого двухъядерного процессора, а после его распространения начать постепенно сходить на нет в пользу разработки на функциональных языках с декларативным параллелизмом — то есть не требующем внимания программиста или ручного раскидывания потоков по ядрам. Развитие ФП наконец-то должно было перестать быть самодеятельностью энтузиастов и НИИ, а стать мейнстримом и получить поддержку со стороны ОС и прочих сред выполнения.

Сегодняшняя популяризация ФП-языков вроде Haskell и Erlang показывает, что интерес к направлению есть, но на мой взгляд, он недостаточен. Чтобы ФП стало массовым, оно должно повернуть лицом к рядовому программисту, стать менее камерным, элитарным и запутанным. Эта проблема может быть решена созданием инструментов, позволяющих решать задачи в той же системе ценностей, что и сейчас, но используя ФП. А начать нужно с языка, с нацеленного на замену императивного программирования функциональным, вплоть до преподавания ФП в школе. В силу возраста уже не все помнят, но когда-то преподавание информатики и программирования в школе тоже было из области сказок, но усилиями профессора Вирта и академика Ершова было превращено в реальность. Новый язык вполне может повторить успех Паскаля, только уже с ФП.

Что предлагаю я: фрактальная ОС

Зачем вообще нужно ООП на уровне ОС? Что под ним понимается? Удивительно, но до сих пор нет четкого термина. Даже больше, мои исследования показали, что у системных программистов есть какой-то другой взгляд на ООП, отличающийся от общепринятого. Поэтому я предлагаю простое и емкое определение объектно-ориентированной ОС: "ОС, позволяющая создавать программы наследованием". То есть, взяли "Блокнот", унаследовали, добавили нужное и получили WordPad; опять унаследовали, опять добавили и получили Word.

Вопрос к скептикам: как вы получаете список файлов? Вызываете FindFirst с маской, а потом много раз FindNext, получая файлы по одному. Есть ли простой способ узнать количество файлов в каталоге? Это в 2013-то году? Если же в ОС будет некий стандартизированный набор контейнеров, получение списка файлов — это получение объекта "список", заполненного объектами "файл". Получение количества файлов в списке также не составляет труда.

На самом деле нечто похожее пытались реализовать еще Microsoft в 1993-1999 годах в рамках проекта под кодовым названием Cairo. Именно для будущей объектно-ориентированной ОС была создана модель COM, потоки NTFS и многое другое. Но Cairo был закрыт, а его наработки частично вошли в то, что мы знаем под именем Windows 2000. Позже ситуация повторилась с так называемыми WinFS и WinFX, разрабатывавшимися в рамках Longhorn, но не вошедшими в состав Windows Vista, а позже выпущенными отдельными продуктами. Почему так?

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

Согласно моим выводам, проблема хрупкого базового класса может быть решена только одним способом — отказом от исходных текстов в пользу обратимого байт-кода. Программирование при этом будет больше похоже на работу с базой данных: вытащил функцию, перевел в текстовый вид, исправил, вкомпилировал обратно. Ядро системы при этом само отслеживает зависимости по наследованию, агрегации, полиморфизму, позднему связыванию и т. п.

Таким образом, разработка нового языка решает не только проблему массового ФП и параллелизма, но и хрупкого базового класса, давая тем самым технологическую основу для создания фрактальной ОС.

Как плюс такая ОС обеспечит многовложенную структуру данных, дав недостающую третью координату — глубину, что и станет основой для создания логически трехмерного пользовальского интерфейса — ZUI. Возьмите любой труд по ZUI — наличие структуры данных там ненавязчиво подразумевается, хоть может и не упоминяться явно. Моя главная книга по ZUI — последняя книга Джефа Раскина, где он еще называет интерфейс Zoom World... Как понимаю, термин ZUI устоялся уже после смерти Раскина.

Что предлагаю я: суперкомпиляция

В ходе проектирования также выяснилось, что генерация конкретного кода из более общего с учетом условий вызова называется суперкомпиляцией (metacompilation или supervising compilation в западных источниках). По-научному такая кодогенерация еще зовется генератором тождественных преобразований. Идея суперкомпиляции и сам термин были придуманы в Советском Союзе и разрабатывались Валентином Турчиным в языке Рефал. В Рефале, как я понял, используется частный случай суперкомпиляции, ориентированный больше на обработку строк. Возможно, что приемы суперкомпиляции уже применялись к языку общего назначения, но мне такие примеры неизвестны. Слышал только, что-то похожее есть в Java-машине HotSpot, но подробно не изучал.

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

Суперкомпилятор позволит избавиться от проблемы недостаточной производительности JIT, на что жалуются пользователи JVM и .NET. При этом качественный JIT на движке суперкомпилятора создать можно, а вот наоборот — нет. Разрабатываемый язык специально затачивается под суперкомпиляцию, переводя многие знакомые программистам вещи, реализованные в обычных языках "в лоб", на логический, понятийный уровень.

Заключение: что сейчас

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

Конкретно сейчас разрабатывается библиотека CoreLite и некоторые сопутствующие утилиты, одновременно помогающие развитию CoreLite. В CoreLite частично отрабатываются идеи ООП, тонкой нитью намечается будущий API языка и общие подходы к решению задач — культура. Культурная составляющая вообще очень важна в технологических проектах, а уж в нацеленных на лидерство — особенно.

После CoreLite будет реализован вики-процессор — компилятор вики-разметки, разработанной в рамках проекта. Вики-процессор позволит сделать сайт с документацией, работающий поверх SVN. Кроме того, библиотека вики-процессора будет использована и в компиляторе, поскольку вики-разметка встроена в язык программирования — в нем есть понятия вики-текста (форматированный текст) и вики-комментариев. Вики-разметка имеет строгий синтаксис и подразумевает леворекурсивный разбор, поэтому на ней также будет отрабатываться и эта часть будущего компилятора.

Работающая инфраструктура документирования даст основу для оформления спецификации языка и байт-кода, которые проработаны пока частично. С позиций сегодняшнего дня видится, что разработка спецификаций будет идти одновременно с реализацией в коде. Как будет на самом деле, не знаю. Что дальше будет — также непонятно.

(вопросы)