LINUX.ORG.RU

Модульность-3

 , ,


2

4

Продолжаю мучаться с системой модулей. Уже почти в депрессию впал - настолько это оказалось трудно.

Как будет устроен файл в Л2

Кусок кода делится на интерфейс и реализацию. Интерфейс и реализация находятся в разных файлах (как в С). Сборка происходит путём построения графа «зависимых действий».

Структура файла примерно такая:

// -*- для_чтения : "зависимое_действие1 ... зависимое_действиеN"; -*-
пространство_имён ИМЯ;
зависит_от зависимое_действие1 ... зависимое_действиеN ; 
... собственно код ... 

В общем-то это похоже на C с его инклюдами.

Зависимые действия

Зависимое действие - это файл (цель) и указание, что с ним нужно сделать. Что можно сделать?

1. Прочитать - это означает, что файл будет распарсен и записан куда-то в память.

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

Зависимости в С и в Лиспе

И вот тут у меня вопрос. В С просто указывается имя файла, а дальше система сама ищет его по путям.

В лиспе же есть «системы», хотя их надо бы назвать «модулями».

Система в лиспе является набором файлов и в то же время единицей зависимостей для сборки образа. Внутри системы - свои зависимости между файлами.

Лисп ищет систему (по путям или другим способом). Внутри системы имена файлов заданы жёстко.

Иллюзия циклических ссылок

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

unit b; interface uses a; 
end. {EOF}

unit a; interface ; implementation uses b; 
end. {EOF}

Казалось бы, это циклическая зависимость. На самом же деле Дельфи компилирует интерфейс и реализацию отдельно и необязательно сразу, а зависимость возможна только от интерфейса. Поэтому это _не_ циклическая зависимость.

В Лиспе тоже надо отделить интерфейс от реализации системы

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

Тогда на лиспе стало бы легче управлять системами. Не считая, конечно, того, что в Дельфи нужно писать меньше слов.

А что делать в Л2

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

Вижу два варианта:

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

2. Сделать как в лиспе, т.е. ввести два уровня иерархии - систему и файл. Система содержит свой файл .asd. Но! Важное отличие от лиспа состоит в том, что система не является единицей сборки, а служит лишь для поиска файлов. Например, если мы нашли где лежит mysystem.asd, то файл mysystem.myfile.л2 находится там же. А, скажем, mysystem/dir1/f2.л2 - находится в подкаталоге dir1.

Зависимости же задаются в виде

действие(система.файл_внутри_системы)

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

При этом где-то должно храниться знание о том, где лежит данная система. Но в asdf эта задача уже решена (даже слишком уж навороченно решена).

Собственно и вопрос - надо ли морочиться с «системами» или достаточно файлов? И может быть, кто-нибудь может это соотнести с другими языками (не знаю, как это сделано в Java и C#).

★★★★★

Последнее исправление: den73 (всего исправлений: 2)

Как же сделать, чтобы было хорошо, в новом языке?

Сделать модуль first-class citizen, не привязывать к файлам, не делить на интерфейс/реализацию.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

расширю: отринуть понятие модуля вообще и сделать «модуль» просто evaluatable кодом который возвращает объект-интерфейс для его использования. расклад этого кода по файлам считать удобной условностью.

t184256 ★★★★★
()

В Лиспе тоже надо отделить интерфейс от реализации системы

шёл 2016й год...

Как же сделать, чтобы было хорошо, в новом языке?

я уже кидал, как это реализовано в racket

lazyklimm ★★★★★
()
Ответ на: комментарий от lazyklimm

я уже кидал, как это реализовано в racket

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

Сделать модуль first-class citizen

Никогда точно не знал, что есть first-class. Если имеется в виду API для работы с модулями с функциями «выгрузить», «загрузить», «найти по имени», «показать зависимости», то это скорее сахар, но не ответ на вопрос «а как должна быть устроена система модулей».

не привязывать к файлам

Ты имеешь в виду иметь возможность сделать один модуль из нескольких файлов? Или возможность дополнять модуль из любого другого места? Или что?

не делить на интерфейс/реализацию.

Здесь я уже принял решение, делить.

den73 ★★★★★
() автор топика

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

Deleted
()
Ответ на: комментарий от Deleted

не только в эрланге, но проблема у ТС-а не столько в экспорте необходимых, сколько в потенциальных конфликтах имён

lazyklimm ★★★★★
()

В общем-то это похоже на C с его инклюдами.

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

anonymous
()
Ответ на: комментарий от lazyklimm

Приведи пример.

Если мы в эрланге импортируем (заинклудим) модуль, дальше мы его функции используем как:

имямодуля:названиефункции(аргументы)

Deleted
()
Последнее исправление: merhalak (всего исправлений: 2)
Ответ на: комментарий от lazyklimm

Ага. Для другого импорта там есть немного другой синтаксис.

То было include, а импорт берет из другого модуля функции и юзает их как локальные (не все, а которые ты указал)

-import(Module,Functions).

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

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

Deleted
()
Последнее исправление: merhalak (всего исправлений: 4)
Ответ на: комментарий от Deleted

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

у меня своя раскладка, с английской пунктуацией :)

lazyklimm ★★★★★
()
Ответ на: комментарий от lazyklimm

но проблема у ТС-а не столько в экспорте необходимых, сколько в >потенциальных конфликтах имён

Это я уже одолел вроде (правда получается аскетично, но лучше чем в Дельфи, а Дельфи вполне можно работать): https://bitbucket.org/budden/l2/src/default/doc/описание-языка/пространства-и...

Вообще я стараюсь придерживаться следующих принципов:

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

- применять на первом этапе наиболее простое решение, позволяющее начать работу; но подумать о том, что предстоит добавить хотя бы на втором этапе

- выбирать только то, что проверено практикой

- придерживаться статического, а не динамического, везде, где только можно; я делаю не динамический язык, а статический язык с динамической реализацией.

den73 ★★★★★
() автор топика
Ответ на: комментарий от Deleted

имя исходника==имя модуля

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

не разделяй реализацию и интерфейс

Это всё равно понадобится при closed source.

в начале исходника делаешь export для тех методов

Небольшой секрет состоит в том, что я хочу сделать как в 1С: атрибут «экспорт» делает данную сущность экспортируемой. Но при этом (в отличие от 1С, С и Дельфи) одним из этапов сборки будет генерация отдельного файла ".h" на базе этих атрибутов.

den73 ★★★★★
() автор топика
Ответ на: комментарий от Deleted

юзай эрланг как базу (тут очень многое хорошо продумано)

Эххх. Это ж надо его осилить сначала. В лиспе вроде тоже некоторые вещи неплохо продуманы. Видимо, придётся почитать. Есть ли короткая книжица на Русском?

То было include, а импорт

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

den73 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Взять для модулей за образец язык без модулей,

Можно считать .h интерфейсом, а реализация, конечно, где придётся. Тогда получаем некое приближение к модулям. Во всяком случае, если С до сих пор доминирует, а языки с модулями прозябают, это повод задуматься, в числе прочего, что не так с концепцией модулья?

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Тогда можно как то так:

(модуль ИмяМодуля
     (ТелоМодуля))
или:
модуль ИмяМодуля {
    ТелоМодуля
}
или:
модуль ИмяМодуля:
    функция ИмяФункции1(аргументы):
        шаг1,
        шаг2,
        ...
        возврат X;

    функция ИмяФункции2(аргументы):
        шаг1,
        шаг2,
        ...
        возврат X.

Deleted
()
Ответ на: комментарий от Deleted

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

модуль a; 

den73 ★★★★★
() автор топика
Ответ на: комментарий от Deleted

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

Думаю, что-то вроде такого (как вызов верхнего):

ИмяМодуля_ИмяФункции(аргументы)

Deleted
()
Ответ на: комментарий от den73

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

Хотя мне самому это не нравится немного.
Разве что:

модуль ИмяМодуля:
    экспортируется([ИмяФункции1/arity, ИмяФункции2/arity])
    функция ИмяФункции1(аргументы):
        шаг1,
        шаг2,
        ...
        возврат X;

    функция ИмяФункции2(аргументы):
        шаг1,
        шаг2,
        ...
        возврат X.
или
модуль ИмяМодуля:
    экспортируется функция ИмяФункции1(аргументы):
        шаг1,
        шаг2,
        ...
        возврат X;

    экспортируется функция ИмяФункции2(аргументы):
        шаг1,
        шаг2,
        ...
        возврат X;

    функция ИмяФункции3(аргументы):
        шаг1,
        шаг2,
        ...
        возврат X.

Deleted
()
Последнее исправление: merhalak (всего исправлений: 3)
Ответ на: комментарий от den73

Ну или не «экспортируется», а «внешняя» или «публичная».

Deleted
()
Ответ на: комментарий от Deleted

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

Про это знаю. Это - экспериментальный сахар, не проверенный временем. Я не рискну.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Ну тогда указывать «внешняя» для экспортируемых функций.

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

Кстати, старайся, чтоб твой синтаксис можно было описать КСГ.

Deleted
()
Последнее исправление: merhalak (всего исправлений: 1)
Ответ на: комментарий от t184256

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

den73 ★★★★★
() автор топика
Ответ на: комментарий от Deleted

Код рабочего примера был написан ещё в июле. Клсс уже отвергнут.

Пока оставил себе свободу выбора:

«Все идентификаторы, не_содержащие_больших_букв, не_начинающиеся_и_не_заканчивающиеся_подчёркиванием, зарезервированы».

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

Вот только что написал ещё кусок кода, любуйтесь: перегрузка операций против пользовательских инфиксных операций

В этом куске полно сокращений, а и то плохо, на лиспе было бы в разы компактнее.

И все эти -> в русской раскладке - ЗЛО.

Да, это я забыл и накосячил, сейчас уберу. Но вторая операция вдобавок к точке точно нужна. Из одиночных букв остались пока не заняты только «%» и "!". Или нужно подключать двойные комбинации. Вот думаю, пойдут ли ".."? Ещё можно сделать как в tcl - отдельный expr для всех арифметических выражений. Тогда в остальном коде «/*-+» освободятся для других дел. Но страшновато.

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

Итак, вопросы про модули:

1. Верно ли, что в С имена файлов .c, .h должны быть уникальны в рамках всего проекта?

2. Хорош ли вариант, когда вместо модулей мы заводим «каталоги», служащие только для поиска файлов, а зависимости между файлами прописываем в самих файлах, в виде глагол(каталог.имя_файла), где глагол - «прочитать» и «загрузить»? Вот пишу и уже вижу, что фигню пишу.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от loz

прнс ништяк, мне ещё вот это

ВебСерверГлотатьОшибки

дико доставляет

lazyklimm ★★★★★
()
Ответ на: комментарий от den73

В общем, никто не помогает, попробую всё же сам родить осмысленный вариант.

Неясность осталась с одним: вот у нас есть интерфейс модуля. Он будет в одном файле. А реализация модуля может быть в нескольких файлах. Где записан список этих файлов? Думается, ему быть негде, кроме как в файле интерфейса модуля. Итак:

файл каталога:

//файл /дир1/мой_проект.каталог
определение каталог "мой_проект";
//больше тут ничего и не надо, это просто файл-метка, считай "ln -s".

//файл /дир1/модуль1.h
заявление_модуля "мой_проект/модуль1";
  пакет "мой_проект/модуль1";
  реализация_состоит_из "мой_проект/модуль1.пакет", "мой_проект/код1.c";
конец_заявление_модуля
//файл /дир1/модуль1.пакет
реализация_модуля "мой_проект/модуль1";   // чьих будешь?
заявление_пакета "мой_проект/модуль1" 
    расширения_чтения "стандарт/операции_с_матрицами";

    // настройка чтения символов без префикса
    использует "стандарт/матрицы", "стандарт/математика";
конец_заявление_пакета
//файл /дир1/код1.с 
реализация_модуля "мой_проект/модуль1";   // чьих будешь?
зависит("библиотека/линейная_алгебра.h"); // касается только данного файла

// собственно код функции
функция ОбратитьМатрицу(м - матрица) - (матрица, в_куче), экспорт; 
  блабла;
  блабла;
  блабла;
конец_функция
//файл /дир1/модуль1.интерфейс - генерируется автоматически обходом реализации

интерфейс_модуля мой_проект.модуль1;
  чтение_зависит(
     расширение_чтения("стандарт/операции_с_матрицами")
     ,пакет("стандарт/операции_с_матрицами")
     ,пакет("стандарт/математика"); 

  интерфейс_зависит("библиотека/линейная_алгебра.h");

  интерфейс_пакета "мой_проект/модуль1"
    расширения_чтения "стандарт/операции_с_матрицами";
    использует "стандарт/матрицы", "стандарт/математика";
    экспортирует 
      функция ОбратитьМатрицу(м - матрица) - (матрица, в_куче);
    конец_экспортирует;
  конец_интерфейс_пакета;
конец_интерфейс_модуля

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

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 2)
Ответ на: комментарий от den73

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

файл /дир1/_мой_проект.каталог

определение каталог _мой_проект;

файл /дир1/_модуль1.h

заявление_модуля _мой_проект/_модуль1
  реализация_состоит_из 
    код1.c;
  пакет
    расширения_чтения _стандарт/_операции_с_матрицами;
    использует _стандарт/_матрицы, _стандарт/_математика;
  конец
конец

файл /дир1/код1.с

в_модуле _мой_проект/_модуль1; 
зависит(библиотека/линейная_алгебра.h); 

функция ОбратитьМатрицу(м - Матрица) - (Матрица, в_куче), экспорт; 
  блабла;
  блабла;
  блабла;
конец
Ваши впечатления?

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 2)
Ответ на: комментарий от den73

Соответственно, для _стандарт/_матрицы будет зависимость от файла .h, а для _операции_с_матрицами нужно ввести какой-то новый тип файла _расширения_чтения. Хотя есть чувство, что в ближайшее время можно будет вовсе без этого обойтись - ридмакросы можно просто импортировать.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

ты используй файлы, именуй хорошо и т.п. просто не enforc'ь это и нигде на это не полагайся.

t184256 ★★★★★
()
Ответ на: комментарий от den73

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

У тебя полный путь модуля ожидается более 4096 символов?

monk ★★★★★
()

текст поста целиком не читал,

но посмотри как сделано в EuLisp github — там более модульный лисп.

anonymous
()
Ответ на: комментарий от den73

конец_интерфейс_модуля

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

anonymous
()
Ответ на: комментарий от den73

Никогда точно не знал, что есть first-class. Если имеется в виду API для работы с модулями с функциями «выгрузить», «загрузить», «найти по имени», «показать зависимости», то это скорее сахар, но не ответ на вопрос «а как должна быть устроена система модулей».

ну например, из паскалей, модульных, компонентных: я про Oberon-2 и модулу-3. и окамлов или скорее SML заодно.

вопрос, является ли модуль типом. в Modula-3 и SML, Ocaml — является (тип как функтор, API модуля это по сути ADT с интерфейсом). если так, то в том же MirageOS — unikernel на Ocaml можно генерировать во время сборки/компиляции модуль стека TCP/IP например как функтор, то есть делать композицию модулей просто функциями высокого порядка (функтор функторов).

если не совсем является, например как в Oberon-2 : то модуль всё равно является единицей для метапрограммирования (а не только компиляции, раздельной, расширяемой). можно изобразить метапрограммирование на модулях, например — см. J. Templ про метапрограммирование в оберон-2, и книгу К. Шипёрски про компонентное ПО, особенно 3 главу про требования к компонентной среде)

метапрограммирование в BlackBox Component Pascal например, используется для кодогенерации GUI: см. про «интеракторы» и порождение форм (стр. 54-57, с примером. также, текст как интерфейс , ещё про блекбокс

если коротко про «интеракторы»: в модуле описываются переменные, типы и процедуры («команды») как экспортированные, потом пунктом меню генерируется форма, в которой переменные становятся полями, записи или объекты — группами, процедуры модуля (команды) — кнопками.

генерируется сама, посредством метапрограммирования. см. исходники блекбокс насчёт модуля Meta, также модуль Modules и т.п. который реализует динамический загрузчик модулей. модули занимают считанные байты, но это не байткод, а просто код + метаинформация импорта/экспорта, с фингерпринтами (чтобы пофиксить проблему «хрупкости базового класса» в общем, и DLL hell в частности.

anonymous
()
Ответ на: комментарий от den73

«что такое модуль и как его надо сделать».

читай про что такое компоненты в КОП, модульность в этом вот смысле, «расширяемых программ».

а также К. Шипёрски книжку про КОП со сравнениями, почему везде модульность неправильная.

(но модуль может состоять из нескольких файлов)

это ты уже какие-то пространства имён накрутил.

anonymous
()
Ответ на: комментарий от den73

в Dylan, например, как и в CL накрутили «библиотеки» потому что единицей компиляции является «пакет», а единицей сборки — «библиотека». поэтому «библиотека» в Dylan — (или система из подсистем в asdf) — показывает как одно отображается на другое.

это уже ближе к «пространствам имён», а не к модульности в стиле КОП.

anonymous
()
Ответ на: комментарий от den73

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

делаешь статический язык из динамического? вот интересный подход описан в книжке про Эльбрус и Эль-76, про ТИПы сама книжка также также

там как раз модуль, компонент, ТИП является first-class value, возвращаемый функцией-генератором, с учётом «времени жизни», ЖЦ модулей. может быть, натолкнёт реализация на полезные идеи относительно «лайфтаймов не как в Rust», например

anonymous
()

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

Но если ты в поисках примеров для подражания смотришь на более традиционные языки - Си и Дельфи - свои 2 копейки вставлю.

То, как модульность (а точнее, её уязвимая имитация на командах препроцессора) сделана в Си (а потом эта гонорея благополучно перекочевала в C++, ибо совместимость) - это просто хрестоматийный пример того, как НЕ НАДО делать модульность. Объектные реализации Паскаля (в т.ч. Дельфи) в этом плане в 1000 раз строже и надёжнее.

И то, что в последнее время в будущий стандарт C++ пытаются таки добавить нормальную модульность (а не её имитацию на инклудах) это подтверждает.

// Вот и анонимус о том же...

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от hobbit

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

К. Шипёрски в книге «Компонентно-ориентированное программирование» и вводит определение «компонента» — как дальнейшее развитие ООП, с ограничениями: запрещено наследование реализации; на нижнем уровне должно зависеть только от интерфейсов; композиция предпочтительнее наследования, как жёсткий/мягкий тип связи; проблема «хрупкости базового класса» (FBC), которую он понимает как синтаксическую и семантическую, и сравнивает компонентные среды между собой, как они эту проблему решают; частный случай — проблема ломающихся бинарных интерфейсов, ABI в новой версии библиотеки; ну и общая идея, что такое «компонент», или модуль с раздельной компиляцией.

Компонентное ПО и компонент — это способ программирования, когда в компонентный фреймворк (в отличие от application framework) «в будущем» можно будет добавить новый компонет, расчитанный на феймворк — и всё будет работать.

то есть расширять систему БЕЗ ПЕРЕКОМПИЛЯЦИИ (привет, пересборка мира в Gentoo) — такие парадигмы как отсюда «синтезирующее программирование, сборочное, композиционноепарадигма, композиционная, конкретизирующее, аспектное»

также статьи в эту тему пишет М. Горбунов-Посадов, про однородный набор 1 2

в этом смысле, «компонентного ПО» — настоящей модульности и компонентности НЕТ НИГДЕ (в современном мейнстриме)

тот же веб, например — развитие пошло, увы и ах — условно, по пути Emacs (только Браузер, а не редактор и JavaScript, а не Elisp) — а так тот же голимый «интерпретатора для веба»

а не по пути compound documents, OpenDoc, SOM и какого-нибудь условного «оберона с гаджетами» как Compound документов, или там откомпилированного Xanadu с Applitudes и ZigZag многомерной базой данных, только с гипертекстом.

Тед Нельсон ещё в 70-х писал «хватит повторять бумагу, нужен многомерный интерфейс»

в этом смысле и Compound документы тоже повторять хватит, нужны какие-то Applitudes поверх и «текст как интерфейс»  — хотя современный мейнстрим недотягивает до нормального , компонентного ПО 90х.

и это печально, да.

anonymous
()
Ответ на: комментарий от hobbit

Я, конечно, никаким образом не шарю в функциональщине

мосты для понимания примерно такие, как в презентации: про разницу между first-class модуль (объект, компонент) как тип (класс) и почему от модулей в стиле оберона/ады перешли к условному Ocaml-у и «модуль как функтор»

а также про функциональные объекты: функциональное + ООП + АДТ + функции, методы, классы (метаклассы) высокого порядка.

отсюда — ссылка ценная, хотя и древняя.

anonymous
()
Ответ на: комментарий от hobbit

ценность функциональщины

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

anonymous
()

В лиспе же есть «системы», хотя их надо бы назвать «модулями».

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

системы описываются как «функциональный объект-компонента-размещение». то есть, функция (а не реализация) отображается на модули, компоненты в «диаграмме развёртывания» или asdf или makefile, или описании «библиотек» в Dylan.

Система в лиспе является набором файлов и в то же время единицей зависимостей для сборки образа. Внутри системы - свои зависимости между файлами.

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

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

anonymous
()
Ответ на: комментарий от hobbit

и какой подход более приличествует благородному ЯП-отпрыску благородного Лиспа - без понятия.

возьмём 3-4 емакса (или даже 5):

* GNU Emacs

* XEmacs

* Emact Кристиана Жульена, автора OpenLisp + OpenLisp

* Ewoks на обероне (который на Ocaml-е) из оксфордского компилятора оберона (на окамле) — модульном, компонентном

* Deuce на Dylan (по мотивам EINE/ZWEI/Portable Hemlock, «Емакса на CL»)

и посмотрим, как там реализованы модули.

GNU Emacs — монолит; подвижки есть в GuileEmac;

XEmacs — FFI и модули на Си

Emact — аккуратные исходники, модульность как в оберонах, OpenLisp интерпретатор ISLISP (обрезанный, без LAP компилятора)

Ewoks — в основном, на обероне

Deuce — в основном на Dylan --- и ядро и модули (пакеты/компоненты)

anonymous
()
Ответ на: комментарий от hobbit

так вот, Столлман за функциональщину в Elisp (условную, ибо там порой и просто императивно/структурное), ибо «Objections to Object Why Objects Has Failed» и т.п.

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.