Моя 3OS

Что в данном документе

Ниже изложено мое личное мнение о перспективах 3ОС. Я старался писать простым и неофициальным языком, но, тем не менее, четко. Если предложения отсюда будут приняты, они войдут в официальные документы 3ОС. Сейчас же я хочу дать свое видение системы, и именно неофициально, чтобы не злоупотреблять служебным положением. ;-)

Сие откровение является плодом долгих раздумий с того времени (примерно), как я предложил разрабатывать ОООС. Ранее я предлагал кое-что по некоторым аспектам системы, но предложения были отрывочными. Давно хотелось сесть и изложить свои мысли целостно, в виде единого документа. Это я и попытаюсь сделать ниже. Логическую стройность мои идеи приобрели не так давно, и думаю, что не сильно устарели за неоправданно затянувшийся период подготовки документа.

В настоящий момент не все идеи проработаны одинаково хорошо, по некоторым пунктам еще есть неясности. Далее в тексте спорные утверждения я буду отмечать знаком вопроса.

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

Для удобства восприятия я разбил мнение на несколько частей. Используемые в тексте термины подразумевают трактовку, даваемую "Лексиконом 3ОС".

Системная часть

Ядро

Системщиком я не являюсь, поэтому глубоко в дебри забираться не буду. Раньше я говорил, что мне все равно, какое будет ядро у 3ОС. Однако, после прочтения некоторой документации и размышлений над концепциями Андрея Милова, я склоняюсь к мысли, что микроядерная архитектура будет для нас наиболее оптимальной. Можно даже сказать, что УО так и просится на микроядерную модель.

Далее я затрону некоторые аспекты реализации ядра и постараюсь дать свою интерпретацию положений об УО.

Объекты

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

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

Удаленные объекты (УО)

УО могут быть двух видов:

С точки зрения клиента, у теневых объектов в другом адресном пространстве расположены методы (код), а у объектов-иждивенцев - данные. В трактовке Андрея Милова, - имеется незавершенность по коду, или данным, соответственно.

УО и интерфейсы

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

Предлагаемая реализация УО в 3ОС отличается от традиционных интерфейсов тем, что происходит на уровне ядра, а не в виде "заглушек", как в COM или CORBA. Использование т. н. сторожевой страницы дает основание говорить, что УО в 3ОС реализованы практически аппаратно, что положительно должно сказаться на эффективности и надежности. Выходит, что нам удалось достигнуть объектной ориентированности на уровне процессора. Я считаю это большим достижением в 3ОС.

Объекты-ижидивенцы

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

Кстати, я постепенно склоняюсь к мысли, что роль объекта в виде тени или иждивенца зависит от точки зрения на него. То, что со стороны клиента является тенью, может (ли?) считаться иждивенцем со стороны сервера УО.

Программы

В "Лексиконе 3ОС" принято, что программы бывают трех видов:

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

Таким образом, в 3ОС должны быть описаны три стандартных класса (интерфейса), от которых будут наследоваться (реализовываться) разрабатываемые программы.

Формат исполняемых модулей 3ОС

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

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

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

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

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

Приведенное описание исполняемых модулей кому-то может напомнить библиотеки типов (type library - TLB) Windows или RPM-пакеты в Linux. Поэтому, хочу отметить два момента:

Программы для нескольких сред выполнения

В предыдущем разделе мы решили, что точкой входа программы в объектно-ориентированной операционной системе является код конструктора. Рассуждая далее, вспоминаем, что каждый класс может иметь несколько конструкторов. Как это согласуется с понятием точки входа?

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

Наследование и полиморфизм

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

Пока неясно, нужно ли создавать отдельные деревья наследования для классов и интерфейсов. Думается, при развитии темы это станет понятно. Самое главное то, что система наследования должна обеспечиваться средой выполнения, поэтому она неизбежно будет иметь некоторые ограничения, чтобы избежать запутанности. Например, множественное наследование в чистом виде, как это делается (?) в C++ на практике может быть реализовано только в виде фактического вложения (?) классов (пре-классов?).

Версии классов и интерфейсов

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

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

Решение проблемы версий в виде отдельного измерения кажется мне пока чисто умозрительным, и больше смахивает на "четвертый постулат ООП". Думается, реальным будет только первый подход, но его гибкость, увы, под сомнением.

Именованные интерфейсы

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

Использование интерфейса как именованного целиком базируется на информации о типе времени выполнения (RTTI). Для каждого класса (интерфейса) записывается:

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

Те, кто знаком с COM, наверняка догадались, что под термином "именованные интерфейсы" скрываются аналоги IDispatch-интерфейсов COM. Изначально эта технология была разработана для языка Visual Basic, но впоследствии получила широкое распространение.

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

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

Информация о типе времени выполнения (RTTI)

Применение RTTI было описано выше. Я не являюсь докой в этом вопросе, и буду краток.

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

Естественно, формат RTTI должен быть един для всей 3ОС, и не зависеть от используемых средств разработки. Наверное, использование RTTI конкретного компилятора допустимо только на первых порах разработки. Впоследствии же, после разработки собственного компоновщика, вопрос может быть решен положительно для собственного, независимого формата.

Физически RTTI представляется мне в виде дополнительного блока данных, присоединяемого к программе (классу). Если наличие RTTI для классов не является обязательным на уровне системы должны быть реализованы средства присоединения и удаления RTTI при компоновке конкретных дистрибутивов и/или установке программ.

Прикладная часть

Здесь хочу позволить себе немного философии. Мне лично 3ОС представляется как единая среда (framework), в которой практически нет границы между системой и программами...

Лет 10-12 тому назад, в книге Питера Нортона я встретил оригинальное объяснение работы виртуальной памяти и подкачки: "в сущности, вся система сводится к набору оверлеев". Из такого короткого и емкого определения сразу все ясно. Важно также другое: человек попытался объяснить что-то новое, используя старый, но понятный всем термин - оверлей. Сейчас, наверное, никто и не помнит про оверлеи, а виртуальную память принимают как данность.

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

А следствия таковы: раз нет границ между системой и программами, которые представляют собой плагины, то получается, что все, кто программирует под 3ОС, пишут систему. Именно так, не больше не меньше. Тут уместно привести пример Форта: вся система и программы написаны на Форте, представляют собой совокупность слов Форта, и не могут существовать друг без друга.

Программы или плагины?

Чтобы ответить на вопрос, давайте вспомним, чем плагин отличается от программы:

В итоге получается, что:

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

Стандартизация

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

ОО-подход к проектированию диктует, что любой модуль должен быть реализацией некоторого абстрактного интерфейса, - иначе система не сможет с ним работать. Значит, в 3ОС придется стандартизировать на уровне системы такие классы, которые обычно считаются прикладными: архиваторы, графические изображения, видео, аудио, кодеки и т. д. И это, не считая традиционных для любой ОС стандартов: интерфейсы драйверов, файловых систем, оболочки пользователя и т. п.

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

Как избежать монстровидности

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

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

В качестве примера могу привести Дельфи: в Интернете и на дисках имеется очень большое число компонентов. Они, как правило, все глючные, даже платные, и профессионалы разрабатывают собственные компоненты, чтобы использовать их потом в своих программах...

На мой взгляд, имеется три средства, которые в совокупности должны не дать 3ОС превратиться в помойку:

Для иллюстрации последнего пункта можно взять любую популярную программу с плагинами: Far или Miranda IM. Плагинов для них куча, но большинство использует только некоторые, хорошо себя зарекомендовавшие и пользующиеся популярностью. Остальные плагины, как правило, или сугубо специальны, или просто не востребованы. Ни Far, ни Miranda IM от количества имеющихся плагинов не страдают, даже наоборот, выигрывают. Монстрами их тоже никто не называет.

Прикладная среда

Разобравшись с философией в предыдущих главах, перейдем к суровой прозе жизни. Как мы заметили, в системе, построенной на плагинах, многие части современных программ будут выведены на уровень системы.

Все классы, рассматриваемые далее, мы привыкли видеть в составе RTL языков программирования (компиляторов) или сред выполнения, вроде Java или CLR .NET. В принципе, и Java, и CLR могут послужить для нас неким протопипом ОО-среды общего назначения.

Менеджер кучи

Как-то, в поисках философского камня программирования я занялся тестированием компиляторов. Самым впечатляющим оказались результаты т. н. "строкового теста" (на конкатенацию строк). Алгоритм прост до гениальности:

  std::string s;
for(int i = 0; i < cnt; i++) { s += string("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); s += string("String test"); s += string("\n"); s += string("is slowest and genius!\n\nTry to make own compiler tests!"); }

Приведен вариант для GNU C++, в тесте VC++ вместо std::string использовался CString. В тестировании также участвовал Delphi, текст программы для которого я опускаю - он практически полностью повторяет приведенный на C++ (использовался встроенный в Delphi тип AnsiString). Скомпилированные программы поочередно запукались на моем домашнем компьютере (Athlon XP 1700+). Результаты выполнения программ при одинаковом числе прогонов:

Странные результаты, не правда ли? Кроме этого, в тестах GNU C++ и Delphi наблюдалась нелинейность возрастания времени выполнения при увеличении числа прогонов - сказывалась работа L2-кэша процессора. С Visual C++ такого не наблюдалось.

Так в чем же дело? Оказывается, узкое место в этом тесте - самонадеянность Microsoft ;-). Для выделения памяти класс CString использует вызовы Heap API Windows, а std::string GNU C++ и AnsiString Delphi - нет. О качестве реализации менеджера кучи Windows, думаю, вы догадываетесь. Если в Windows XP VC-тест хоть медленно, но работал, то в Windows Millennium - просто вываливался с традиционным для этой системы сообщением, что программа наконец-то выполнила недопустимую операцию.

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

Сборщик мусора

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

Появление сборщика мусора в 3ОС - вопрос времени. Может быть, не в первой версии, но он обязательно будет. С точки зрения ОС, сборщик мусора - это еще один менеджер памяти. Если программам разрешается иметь несколько куч одновременно, опциональность сборщика мусора также легко реализуема.

Стандартные контейнеры и обмен данными

Ни одна прикладная программа сейчас не в состоянии обойтись без специализированных классов, таких, как строки символов и контейнеры. Точнее, только контейнеров, т. к. строки символов тоже можно считать контейнерами.

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

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

Забегая немного вперед, отметим, что в разделе, посвященном пространству данных, мы введем понятие устойчивого объекта. Можно сказать, что стандартные контейнеры представляют собой некий аналог устойчивых объектов в памяти. Например, в Delphi VCL связь еще более явная - абстрактный класс контейнера представляет собой также и абстрактный устойчивый объект (TPersistent). Будет ли сделано в 3ОС аналогичным способом, для меня неясно. Но, наличие стандартных контейнеров данных на уровне системы, будет очень полезным во многих случаях, например, для поддержки строк символов на уровне ОС.

Строки

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

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

Юникод имеет несколько вариантов (способов кодирования). UCS32 удобен тем, что:

Я предлагаю исходить из трех постулатов:

Абстрактный класс строки имеет стандартные методы, присутствующие в аналогичных классах C++ и Java. Свойство "символ в позиции n" имеет тип UCS32 для всех строк. Программы, обрабатывающие строки посимвольно, не будут вообще ничего знать о кодировках (например, программа отрисовки символов TrueType/OpenType).

Реализации абстрактного класса строки различаются длиной символа и методом их кодирования:

При присваивании строки с сужением набора символов отсутствующие символы заменяются знаками вопроса или чем-то подобным, как сейчас делают Unicode-программы Windows. Кстати, в 3ОС понятия Юникод- и не-Юникод программ не будет.

Последние замечания касаются однобайтовых строк:

Текстовые файлы

Набившей оскомину проблемы текстовых файлов в 3ОС не будет, т. к. вообще не будет понятия файла, в том числе и текстового. В традиционных системах выбор символов-разделителей приводил к "священным войнам" между сторонниками 0x0D,0x0A, 0x0D и 0x0A. Появление Интернета, кажется, всех примирило - большинство программ воспринимают все перечисленные комбинации.

Другая сторона текстовых файлов - представление в качестве таковых устройств типа терминала. Тут надо провести четкую границу - 3ОС не отрицает существования терминалов, но жестко разграничивает сферу их представления и применения: программы обработки текста работают с объектом "текст", а терминальные программы - с объектом "терминал".

В первом случае, по запросу программы "текст" возвращает количество строк или требуемую строку по индексу. Внутреннее представление текста программу не интересует. Сам текст, кстати, не обязательно может быть простым текстом (plain text), а, например, HTML-объектом.

Терминальная программа, работая с объектом "терминал", может получать его связанным с некоторым физическим или логическим устройством: консоль, порт, сокет. Символ-разделитель является параметром объекта "терминал", задаваемым жестко драйвером устройства или выбираемым по желанию пользователя (зависит от конкретного устройства). То, что находится вокруг терминала, и напрямую с ним не работает, использует объект "текст", и понятие символа-разделителя к ним неприменимо.

Компиляторы и интерпретаторы, требующие т. н. "простой текст", в рамках 3ОС также будут работать с описанным выше объектом "текст". В соответствии с изложенными правилами, внутреннее представление исходников в компиляторе должно базироваться на наборе символов UCS32. Фактическая кодировка исходного текста, наличие или отсутствие какого-либо форматирования (HTML, RTF и т. п.) скрывается от компилятора внутренней реализацией объекта "текст". Да-да, вы поняли правильно - желающие могут набирать свои исходники прямо в RTF или HTML, раскрашивая их во все цвета радуги, используя разные шрифты и другие выразительные средства этих форматов.

Ресурсы

Ни одну современную программу невозможно представить без ресурсов - локализируемых данных, обычно состоящих из наборов строк, сообщений об ошибках, значков, шаблонов диалоговых окон и т. п. В Java понятие ресурсов отсутствует, но фактически реализуется включением в дистрибутив вспомогательных файлов - GIF-картинок, строк сообщений и т. д. Думается, при общей прикладной направленности 3ОС проблему ресурсов нельзя оставлять на усмотрение программистов.

В соответствии с постулатами, изложенными в "Мини-DMM" Андрея Милова, хранимые данные представляют собой образы устойчивых объектов, записываемые методом Write и считываемые методом Read. Ресурсы являются одним из устойчивых объектов. Следовательно, каждому типу ресурсов будет соответствовать отдельный класс, реализующий требуемую функциональность, в том числе и чтение/запись.

Если напрячь воображение, набор ресурсов 3ОС однозначно представляется похожим на файлы, представляющие собой совокупность сохраненных образов устойчивых объектов, например, ресурсы программ Turbo Vision (DOS Navigator, например) или файлы, создаваемые сериализацией объектов MFC (документы Word и Excel).

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

Самое главное:

Национальные и региональные настройки

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

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

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

Оптимизация быстродействия

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

Думается, для снижения накладных расходов на выполнение кода самой системы и ее основных служб можно применить опыт CLR. Т. е. некий класс (или область выполнения) объявляются полностью отлаженными, и не требующими никакой проверки во время выполнения (unsafe в терминах CLR). На этих классах проверка отключается, RTTI не используется, а система начинает работать быстрее.

Единое пространство данных

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

Ранее я предлагал использовать концепцию "контейнер-кодек-поток" (ККП). Похоже, она получила одобрение участников проекта, и теперь считается базовой в 3ОС, наряду с УО Андрея Милова. Поэтому естественно, что приведенное ниже описание будет строиться именно на ней. Можете считать его авторским изложением ККП.

Постулаты пространства данных

В этом разделе я хочу показать, что переименование всем хорошо знакомой ВФС в пространство данных является не просто косметическим изменением или погоней за модой, а чем-то более весомым.

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

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

Поэтому, понятие единого пространства данных 3ОС исходит из следующих постулатов:

Хорошим примером типизированной гетерогенной среды является Web. Все ресурсы, хранящиеся в сети WWW, имеют строго определенный MIME-тип, а стандарты протокола HTTP позволяют получить данные, не заботясь о их конкретном источнике (например, статическая страница HTML, или данные БД, обрабатываемые некой CGI-программой). Перенося идеи, положенные в основу Web, на уровень ОС, получаем единое пространство данных.

Контейнер-кодек-поток (ККП)

Прежде чем начать описание, хочу привести список понятий, раскрываемых далее. Итак, концепция "контейнер-кодек-поток" строится на следующих базовых понятиях:

Рассмотрим их по порядку.

Абстрактный поток

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

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

Не все перечисленные операции применимы ко всем потокам. Могут существовать потоки:

Способность позиционировать указатель на данные является отдельным свойством. По нему потоки подразделяются на:

Понятие абстрактного потока в ККП ничем не отличается от традиционного. Например, адепты UNIX могут считать его обычным потоком UNIX, обернутым в оболочку ОО (хотя это не совсем верно - в 3ОС нет понятия "ОО-оберток").

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

Поток хранения

Поток хранения - это поток, связанный с конечным устройством ввода-вывода. Можно сказать, что поток хранения является прикладным интерфейсом драйвера какого-то устройства или логического модуля ОС.

В концепции ККП поток хранения олицетворяет собой конечную точку ВФС, далее которой идут устройства. Можно сказать также, что на потоке хранения кончается прикладной (высокий) уровень абстракции, и начинается слой драйверов, низкоуровневых служб и т. п.

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

Примеры потоков хранения:

Кодек

Кодеком называется объект, преобразующий данные. По логике, кодек имеет:

Соответственно, кодек реализует два интерфейса потока: один для входа, а другой - для выхода. К обоим потокам применимы свойства абстрактного потока, но с оговорками:

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

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

Примеры кодеков:

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

Возвращаясь к теме строк символов, с точки зрения хранения можно сказать, что 3ОС оперирует со строками UCS32, но позволяет их сохранять при помощи нескольких кодеков. Кодеками в этом случае будут являться реализации кодировок UTF8, UTF16, CodePage и т. д.

Объект данных

Объект данных - это устойчивый объект, содержащий некоторые прикладные (по отношению к пространству данных) данные. Интерфейс устойчивого объекта не отличается от традиционного:

В качестве параметра оба метода получают интерфейс потока ввода-вывода.

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

С прикладной точки зрения, объект данных является минимальным "кирпичиком", конечной точкой и для пространства данных, и для прикладной программы. Дальнейшее деление объекта данных невозможно: то, что находится внутри него, полностью интерпретируется и обрабатывается кодом объекта данных.

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

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

Примеры объектов данных очевидны:

Еще один взгляд на объекты данных рассматривается в следующей главе, посвященной контейнерам.

Следует особо отметить, что, работая с объектами в пространстве данных, прикладные программы не создают экземпляров кодеков или потоков - это за них делает объект данных. В этом и состоит самое главное отличие пространства данных от среды традиционных ОС, где потоки создаются прикладными программами.

Контейнер

Контейнер данных (абстрактный контейнер, далее просто "контейнер") - составной объект данных, т. е. объект данных, состоящий из нескольких вложенных в него объектов данных. Рассуждая от противного, можно также сказать, что объект данных является вырожденным случаем контейнера, содержащего только один объект.

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

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

В концепции ККП контейнер является базовым абстрактным понятием, на котором строятся дальнейшие рассуждения о пространстве данных.

Неперечислимый контейнер

Данный вид контейнера является самым простым в ККП. В соответствии с логикой, считается, что неперечислимый контейнер содержит некоторое число объектов данных, но:

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

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

Примеры неперечислимых контейнеров чаще связаны в сетью:

Перечислимый контейнер

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

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

Аналогичные перечислители используются в Java, и называются итераторами. Перечислитель реализует два основных метода:

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

В ККП перечислимый контейнер является предком для последовательного контейнера и контейнера прямого доступа.

Последовательный контейнер

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

Как говорилось выше, последовательный контейнер "не знает" точного количества помещенных в него объектов, но может их пересчитать по одному при помощи перечислителя. Поскольку фактическое перечисление объектов в контейнере может быть связано с чтением с диска, или посылкой сообщений по сети, введение отдельного класса для последовательного по природе контейнера полностью оправдано.

Примеры последовательных контейнеров:

Контейнер прямого доступа

Перечислимые контейнеры бывают двух типов - последовательные и прямого доступа. Последовательные контейнеры не имеют дополнительных свойств, по сравнению с абстрактными перечислимыми контейнерами. Контейнеры прямого доступа, наоборот, имеют несколько дополнительных методов:

Как видно, прямой доступ к объектам контейнера может осуществляться по индексу. Контейнер прямого доступа является аналогом списков или коллекций в традиционных ОО-библиотеках.

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

Примеры контейнеров прямого доступа:

Иерархический контейнер

Любой перечислимый контейнер может также являться иерархическим. По определению, иерархический контейнер может возвращать перечислители, дающие доступ не ко всем, а только к некоторым объектам данных, отобранных по тому или иному признаку.

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

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

Примеры иерархических контейнеров:

Первичные и вторичные контейнеры

По отношению к помещенным в него объектам данных, любой контейнер пространства данных является:

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

URL

Для именования объектов данных концепция ККП предлагает использовать URL. На то есть три причины:

URL 3ОС состоит из двух частей:

Используются следующие служебные символы:

Все остальные символы интерпретируются, как есть. Здесь и выше под словом "символы" подразумеваются символы UCS32. В случаях, когда использование UCS32 невозможно, символы не из набора ASCII представляются их кодами, в соответствии с существующими правилами формирования URL.

Например, адрес сайта 3ОС http://www.3os.ru/ может быть преобразован к виду: http:www.3os.ru. Аналогично, почтовая ссылка mailto:coordinator@3os.ru может быть записана как mailto://coordinator@3os.ru/. В 3ОС обе записи равнозначны и поддерживаются на уровне пространства данных.

Данная концепция не устанавливает ограничений на длину URL. Однако, в целях совместимости с существующими стандартами, некоторые пространства имен могут накладывать свои ограничения на длину URL.

С точки зрения ККП важным является также то, что в URL перечисляются только контейнеры и объекты данных, кодеки и потоки лежат на более низком уровне. Поскольку мы ранее причислили объекты данных к контейнерам, можно сказать, что в URL указываются только контейнеры.

Корень пространства данных

В традиционных ВФС существует понятие корневого каталога или просто корня. К нему монтируются узлы дисковой ФС и отображаемые устройства.

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

Корень пространства данных 3ОС представляет собой перечислимый контейнер, содержащий пространства имен. Опираясь на правила URL, принимается, что корень пространства данных обозначается знаком ":" (двоеточие).

С альтернативной точки зрения, корень пространства данных также может рассматриваться как диспетчер пространств имен.

Пространство имен

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

В соответствии с приведенными выше правилами, пространства имен обозначаются идентификаторами, после которого идет двоеточие. Примеры пространств имен:

Поскольку пространства имен являются контейнерами, к ним применимы все свойства контейнеров. В приведенном выше примере: file:// и user:// - перечислимые иерархические контейнеры, а остальные - неперечислимые иерархические.

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

В 3ОС наверняка будут существовать специализированные пространства имен, определяемые системой. Например, мне видится целесообразным монтирование пространства имен, представляющего аналог реестра Windows. Самое главное - выбрать правильный стиль именования и разобраться со стандартами префиксов URL, которые и являются в 3ОС идентификаторами пространств имен.

Для целостности картины введем также понятие неименованного пространства имен. Для каждой программы неименованное пространство является пространством имен по умолчанию. Пока неясно, какие объекты оно должно содержать. Объекты в неименованном пространстве имен имеют URL без начального префикса. Работа неименованного пространства имен обеспечивается специальным диспетчером, создаваемым системой при запуске программы. Можно сказать, что диспетчер неименованного пространства имен является частью среды выполнения программы. Неименованное пространство имен обязательно является отображаемым, т. е. вторичным контейнером объектов. Отображая неименованное пространство имен на разные фактические пространства, получаем ОО-аналог переадресации устройств ввода-вывода в UNIX. Но в UNIX мы ограничены консолью и дисковыми устройствами (отображаемыми как диски), а в едином пространстве данных такого ограничения не будет.

Синтаксический разбор URL

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

Как видно из описания, эта схема не имеет ограничений ни на класс используемых контейнеров, ни на количество их вложения. Следует также учитывать, что иерархические контейнеры могут интерпретировать сразу несколько частей (токенов) URL за один раз, поэтому четкой связи "один токен - один контейнер" не существует.

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

Кэширование и оптимизация

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

Поскольку хранение данных в виде набора байтов идет вразрез со строгой типизацией, для кэширования пространства данных 3ОС предлагается воспользоваться т. н. объектным кэшем, который описывается ниже. Объектный кэш может применяться как для кэширования программ, так и данных, поскольку и те, и другие в 3ОС представляют собой объекты.

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

Объектный кэш

Суть объектного кэша в том, что данные в памяти представляются не в виде низкоуровневого набора байтов, а в виде экземпляров программ или объектов данных. Грубо говоря, вся процедура кэширования сводится к тому, что экземпляры объектов после использования не уничтожаются, а продолжают находиться в памяти до тех пор, пока не потребуется ее перераспределение. Не могу вспомнить точно, но где-то такая технология точно применялась, у меня даже стоит перед глазами пункт в настройках "Weak package loading".

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

У объектного кэша оба пункта совмещены, т. к. данные хранятся сразу в виде готового объекта, для использования которого никаких дополнительных действий не требуется.

Можно сказать, что кэширование на уровне объектов дает практически двукратную экономию памяти по сравнению с традиционным кэшем.

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

Следствия кэширования объектов

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

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

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

ККП и доступ к данным

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

Какие при этом будут произведены действия?

Все начнется с синтаксического разбора URL, для чего в память последовательно будут загружены все контейнеры, стоящие на пути к объекту. Ранее мы говорили, что именно контейнеры и объекты данных являются источниками или приемниками на всем пути от носителя к программе. Экземпляры кодеков и потоков создаются именно ними. Для сокращения времени доступа к объектам данных и снижения накладных расходов, предлагается задействовать метод оптимизации, названный ранее отложенным чтением из вложенных контейнеров.

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

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

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

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

Именование объектов и типизация

Как говорилось выше, строгая типизация является основой пространства данных. Также было принято, что для именования объектов в пространстве используется URL. URL содержит имена контейнеров на пути к объекту данных, а также имя самого объекта данных. Однако, URL не предоставляет никаких сведений о типе объекта. Вспомним Web - при обращении по некоторому URL, браузер вначале запрашивает MIME-тип документа (объекта данных), интерпретирует его, и только потом начинает его загрузку и обработку.

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

Выделим следующие важные следствия именования объектов при помощи URL:

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

Моя концепция предлагает следующее:

Следствия:

Примеры:

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

Автоматическое распознавание типа данных

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

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

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

Создание и поиск объектов

Как было сказано выше, для описания процесса создания и поиска объектов можно разработать специальный язык. Возможно, именно этот язык и будет называться DML. ;-)

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

Далее мы рассмотрим, что должен описывать наш язык для каждой операции, объявленной специализированной:

Создание объекта

Для создания объекта в пространстве данных требуется следующая информация:

В процессе создания объекта нас ждут следующие трудности:

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

Не все контейнеры являются универсальными, т. е. могут принимать объекты ограниченного набора типов. Если создаваемый объект не может быть помещен в контейнер, на который указывает URL, контейнер должен вызвать исключение, которое будет передано вызывающей стороне. Сам объект при этом создан не будет.

Поиск объекта

Для поиска объекта в пространстве данных требуется следующая информация:

Из приведенного списка только URL является обязательным параметром, а все остальные могут быть опущены.

В процессе поиска объекта возможна только одна ошибка, связанная с идеологией единого пространства данных - URL указывать на неперечислимый контейнер. Как следует из определения, поиск объекта может производиться только в перечислимых контейнерах. Поскольку пространство данных может содержать в себе и неперечислимые контейнеры, поиск по всему пространству данных невозможен.

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

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

Продолжение

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