OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Пятница, 20 Октябрь, 2017 06:24

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 72 ]  На страницу Пред.  1, 2, 3, 4
Автор Сообщение
СообщениеДобавлено: Четверг, 12 Октябрь, 2017 16:15 

Зарегистрирован: Вторник, 30 Июнь, 2009 14:58
Сообщения: 1427
Тогда я совсем перестал понимать что представляют из себя интерфейсы в модуле 3.

Partial Types - это же просто раскидать по файлам.
Это и в Go можно (просто немного иначе).

А интерфейсы у объектов то есть? Или там модуль - это объект?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 12 Октябрь, 2017 19:49 

Зарегистрирован: Вторник, 26 Январь, 2010 09:31
Сообщения: 398
Интерфейс ОБЪЕКТА в М3 это подтип некоторого типа, то есть тип содержит все, определенные для него подтипы. Тип в М3 можно сужать, образуя подтип(интерфейс например), который служит для тогоже, что и интерфейсы в других яп, для инкапсуляции, для создания иерархий и тп, и открывать -revelation, для реализации. Какие подтипы будут включены в окончательный тип определяется сборочным скриптом. Клиенты в дальнейшем импортируют конкретный интерфейс и видят только то, что позволено. Инкапсуляция без протечек.Интерфейс - это часть, объектного типа, находящаяся в интерфейсном модуле, понятно, что один интерфейс могут разделять множество объектных типов. Интерфейс, еще раз - это подтип, он сужает видимость типа, но сам по-себе это такой же тип данных и его можно использовать и передавать в него объекты совместимых типов.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 12 Октябрь, 2017 21:50 

Зарегистрирован: Вторник, 30 Июнь, 2009 14:58
Сообщения: 1427
Kemet, кусок кода нужен для ясности

add:
сам нарыл: http://www.angelfire.com/tx4/cus/shapes/modula3.html


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 13 Октябрь, 2017 06:20 

Зарегистрирован: Вторник, 26 Январь, 2010 09:31
Сообщения: 398
ilovb писал(а):
Partial Types - это же просто раскидать по файлам.

Нет, не только раскидать, в этом мало смысла. Смысл в инкапсуляции. Получившиеся "частицы типа" это же суть интерфейса к объекту. Можно объявить переменную с таким partial type. И использовать только предоставленный интерфейс( вернее частицу ), хотя там и лежит экземпляр полного типа.
То есть partial types позволяют сужать доступ, разделять на логические части.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 13 Октябрь, 2017 20:10 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 171
prospero78 писал(а):
Динамические языки, аля питон -- обладают строгой типизацией. Если это целое -- то это целое, и никакая не строка. Но если сделаем принудительное приведение -- опля -- и уже строка!) И этим динамическая типизация страшна.

В дополнение, часто в скриптовых языках увлекаются "гибкостью" и перегружают операции в стиле "a*n", где a - строка, n - число. Ошибся с типами, подразумевая умножение двух чисел, в результате нет ошибок (исключений) и образуется строка, т.к. "умножение" вызывает ф-цию аля replicate -- "ab"*3 => "ababab" (возможно при сохранении результата, т.е. при присваивании, обнаружится несостыковка. дай Бог).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 13 Октябрь, 2017 20:23 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 171
Предлагаю взглянуть на эту работу:
CZ: Multiple Inheritance Without Diamonds

Там разобраны основные популярные техники (но не все) организации интерфейсов как обобщённых алгоритмов, а именно: множественное наследование, "trait" (абстрактные типы, "типажи" как в Rust, классы типов как в Haskell, протоколы, прототипы, интерфейсы), "mixin" ("подмешивания", "примеси"). Указаны ключевые проблемы, и предложен свой вариант реализации множественного наследования с предохранением от классических граблей от "ромбов". Прежде всего -- проблемы с конструкторами данных. Ну и с именами конфликтующих элементов, хотя здесь принципиально решений всяких много, а то даже шире -- как в Scala с "path-dependent types", здесь кратко пример (если концепция незнакома):
http://danielwestheide.com/blog/2013/02 ... types.html

В двух словах. Выделяются две семантические языковые роли у типа-класса: как единица (повторного) использования и как единица создания экземпляров-объектов. Абстрактные классы лишь в первой роли, однако могут содержать свои данные (ессно и операции), но не могут вызывать конструкторы данных и "требуют" организацию инициализации у своих потомков. Введено два ключевых слова: require -- понятие лишь субтипа, extends -- в т.ч. и субкласс (т.е. и возможность создания экземпляров). Имеется некий контроль типов (недопущение ромбов-субклассов), определена политика диспетчеризации мультиметодов (особенно см. гл.5 "Example: Abstract Syntax Trees").
В общем, техника максимально близка к "классическому" ("статическому") ООП.

В IT также имеется и "динамическое" ООП. В качестве примера (диалект ML для генерации С++):
objects: http://felix-lang.org/share/src/web/tut ... index.fdoc
polymorphism: http://felix-lang.org/share/src/web/tut ... index.fdoc

Первая ссылка -- вариант ОПП в "прототипном" стиле (аля JavaScript, решений для Lua и т.п.). Фактически -- абстракция над записями (record или структуры), позволяющая динамически создавать/удалять "потомков". Только одиночное наследование -- каждый тип подразумевается как роль, объект в целом обладает множеством ролей. Интерфейсы как в Java, или аля как было в COM. Возможна не только "реализация" интерфейса в типе, но и "преобразование" типа для интерфейсной переменной (в общем случае её можно понимать как структуру с указателями на функции). Интерфейс может быть определен (составлен) без оглядки на реальные структуры объектов, их иерархию и т.д. (там даже есть примеры, когда в одной подсистеме (программе, или аля DLL) объекты "живут" по-своему согласно своим типам, а в другую подсистему передаются для взаимодействия уже под нужными интерфейсами согласно местной "точки зрения" в данной системе). Чтобы не было "случайных утиных" типов требуется явное приведение типа (разработчик "номинативно" подтверждает семантику).

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

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

Однако конкретно в данном случае в классах типов имеются универсальные недостатки, впрочем как и во многих популярных языках/платформах с trait-ами, не имеющих данных (а те, которые имеют -- абстрактные классы, разобранные в CZ, в той же статье указано и о проблемах trait-ов без данных). На примере того же Rust -- ниже ссылка на предложение ввести в trait-ы виртуальные поля данных:
https://github.com/nikomatsakis/fields- ... -traits.md

Кроме конкретных технических нюансов данной платформы (некоторые проблемы с типизацией, "borrow checker") в целом без виртуальных полей возникает потребность явно вводить всякие функции-"accessor"-ы (и соответственно их реализовывать), к тому же семантически необходимо их как-то всё-равно выделять и разруливать политику public/ptotected или private, понимая, что касается именно реализации, а что именно доступа со стороны клиентов будущего типа.
Т.е., растут аппетиты, хочется чего-либо аля "mixin", как во всяких скриптовых языках или вот на примере языка D -- текст примерчика (просто под руку попался) выложили в каментах к статье опять же вокруг Rust-а:
https://habrahabr.ru/post/309968/#comment_9808142

Но в D есть некая каша -- "binding" полей косвенный через совпадение имён (может и есть какое-то явное управление), наблюдается прямая инициализация собственного состояния (однако нюансов не знаю, возможно автоматом ничего не исполняется в плане вызова конструкторов). В статейке про CZ хорошо разложено, почему инициализацией должны управлять только лишь "единицы создания экземпляров" -- иначе множественное наследование не разрулить. Отсюда, кстати, не получится соблазн -- иметь "типаж" (trait) как абстрактный тип, но при случае он же может быть и полноценным типом (т.е. trait как полноценный готовый type). Однако реализация (использование) trait-а м.б. тривиальной -- добавить инициализацию.
Поэтому в целом логично, если в trait-ах будут лишь виртуальные структуры. Правда, язык должен быть по-удобнее, в дополнение к стилю (аля как предлагается в Rust):
Код:
trait Trait {
    field1: Type1,
    field2: Type2;

    fn foo();
}
...
impl Trait for Type {
    field1: self.foo.bar,
    field2: self.baz
}

не помешают и прочие стили параметризации аля ML, напр., как "аргументы":
Код:
trait Trait(field1: Type1, field2: Type2) {
    fn foo();
}
...
struct Type {
    ...
    impl Trait(self.foo.bar, self.baz) {
        fn foo() => ...
    }
}

(trait-ы рекурсивно по своей иерархии передают параметры или инициализируют их явно, типы-кортежи для вирт. полей или параметров, ессно, могут определяться отдельно). Нужны и прочие фишки, как partial-определение типов (подключение функционала по потребности).
Кстати, стоит принципиально отличать подобные "типажи" от "наследования" в виде "embedding" как в Go ("композиция" со включением полей плюс автоматом полученный интерфейс наружу с неким разруливанием имён):
https://github.com/luciotato/golang-not ... ter/OOP.md

В общем, такая общая картина.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 13 Октябрь, 2017 20:26 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 171
У меня об Обероне слабые представления, особенно насчёт runtime-meta системы. Не знаю, насколько удобна или целесообразна потенциальная реализация неких интерфейсов, к примеру, по мотивам "фасетов" ранее здесь в теме. Если в языке нет базовых конструкций, то, скорее всего, придётся строить что-то вроде "прототипного" ООП на процедурах и структурах, может быть в стиле множественного наследования как в CZ выше.

В качестве, как минимум, "математической постановки" есть смысл взглянуть на вариант "структурной типизации" в виде "row polymorphism" (последняя статья про реализацию "записей" с поддержкой множества вариантов "полей" -- те же "гибкие объекты"):

Objects and Aspects: Row Polymorphism
Row Polymorphism Isn't Subtyping
Extensible records with scoped labels


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 14 Октябрь, 2017 11:33 
Аватара пользователя

Зарегистрирован: Воскресенье, 12 Апрель, 2015 18:12
Сообщения: 1043
Откуда: СССР v2.0 rc 1
Безусловно, всё это сделать в Обероне можно. Он достаточно прост для таких задач.
Вопрос только, зачем? Простота -- залог здоровья. Борис, на самом деле, хорошие темы цепляет. Только, имхо, не может вылезти из колеи толстых и наглых))


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 18 Октябрь, 2017 18:47 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 171
prospero78 писал(а):
Вопрос только, зачем? Простота -- залог здоровья.

Так ведь абстрактные операции и нужны для упрощения реализации сложных вещей. Их проблематика была разобрана ранее здесь в теме в рамках этой публикации:
viewtopic.php?f=30&t=6131&start=20#p102274
viewtopic.php?f=30&t=6131&start=40#p102355

Там речь об универсальных сообщениях и их специализации для конкретных объектов (типов). Иными словами -- перегрузка операций (со всеми семантическими оттенками, напр., операция draw может быть как у типа Shape, так и у Cowboy. Или же интерфейс Stack может отличаться в зависимости от семантики реализации (bounded или unbounded) и т.д.).

Как раз в тему, обратил внимание по соседству на проект oberonjs и на предлагаемые там расширения:
https://github.com/vladfolts/oberonjs/wiki/Eberon

Показательна пара моментов. Во-первых, для ООП введено понимание методов, конструкторов, SELF и SUPER -- уже облегчение перегрузки операций в потомках. Не помешает "расширение" (наследование) и самих экземпляров-объектов (не только типа), как было представлено выше в рамках Felix:
http://felix-lang.org/share/src/web/tut ... index.fdoc

А если ввести и подобные интерфейсы (по той же ссылке выше), то, как минимум, в ряде случаев ликвидируется типовой недостаток предлагаемого стандартного паттерна "generic message bus", как он указан, напр., здесь:
https://github.com/vladfolts/oberonjs/w ... -Narrowing

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

И обращает внимание в проекте oberonjs введенный тип STRING:
https://github.com/vladfolts/oberonjs/w ... on-Strings

Именно отсутствие удобных средств перегрузки операций вынуждает подобные решения реализовывать на уровне языка или компилятора, а не как библиотеки. На сегодня в IT уже отшлифованы принципы переопределения, в т.ч. и в случаях сложных правил, к примеру, как для математических функций/операторов. Напр., в Julia -- удобные соглашения или стандартные операции приведения/оценки типов -- паттерн "сonversion and promotion" (плюс понимание абстрактных классов или интерфейсов, типажей и т.п.):
https://docs.julialang.org/en/stable/ma ... promotion/

Подкрепляются возможности прочими приёмами полиморфизма, как множества типов, функции типов -- опять же на примере выше в рамках Felix:
http://felix-lang.org/share/src/web/tut ... index.fdoc

Перегрузки опасны неявные, непреднамеренные. К примеру, в некотором scope пользовались функцией аля:
f(x: double): double => ...

, которая может принимать и int. Затем после изменений косвенно в scope попадает новая функция вида:
f(x: int): int => ...

, которая незаметно "перетянет" на себя "int"-применение. Однако в целом в IT решения известны, в том же Pascal-е для явности требуется указание "overload" (как и "override"), или же в Felix выше перегрузки контролируются через "open" и "close" (прежде всего для "классов типов". И в целом видится, что использование принципа "закрытия" (close) позволяет контролировать "безопасность" -- к примеру, "закрывать" (в сборочных файлах) для определенного пространства имён модулей некоторые группы перегрузок, в т.ч. какие-то "системные" или "виртуальные" -- не давать возможность использования "опасных финтов").

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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 18 Октябрь, 2017 22:41 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2395
Откуда: Россия, Ярославль
Жаль, что я не веду статистики со ссылками, но каждый раз вижу, как открытая возможность улучшить "что-то" в Обероне порождает улучшательский раш у аудитории, и уже не спастись, коготок увяз, каждый пункт сообщения о языке подвергается пересмотру с учетом современных тенденций и обязательно приводит к упрощению, улучшению, облегчению и вообще. Еберон, проект-издёвку (кто помнит историю создания, тот понимает) уже приводят в пример, мда.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Октябрь, 2017 19:05 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 171
Я не пользователь Оберон-платформы, не в курсе, что Еберон -- "издевательство" над Обероном (хотя странно как-то, но мне неизвестны политические заморочки и в таковы не лезу).
Выше были лишь доводы насчёт абстрактных типов в целом, и особенно с полной поддержкой со стороны компилятора (и их семантическая первичная проблематика не зависит от конкретного языка).


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Октябрь, 2017 19:15 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 171
Кстати, насчёт библиотечного решения как runtime-полиморфизма (или "фасетов" здесь ранее) -- вспомнилась "классика" -- мультиметоды в lisp, а в Clojure ещё и упрощённые "классы типов" (интерфейсы-типажи или там это "протоколы") реализованы. Здесь кратко обо всём:
http://alexott.net/ru/clojure/clojure-intro/#sec15

Там по ссылке ещё указано примечание по поводу реализации методов по умолчанию:
http://fulldisclojure.blogspot.com/2010 ... ocols.html

Если есть возможность (ну и потребность) с помощью каких-то хаков выстраивать подобные декларации, то стоит обратить внимание -- принципы давно опробованы, API устоявшееся и т.д.

И заметил уточнения, что конкретно имелось ввиду под "утиностью":
viewtopic.php?f=12&t=6127&p=102197#p102186

В таком стиле, как в Go, отсутствует строгая статическая типизация в интерфейсах, о чём, видимо, и был здесь спор ранее. Согласно примеру по ссылке, если интерфейсы определены независимо (и пусть хоть в разных модулях), то это не только технически, но и, прежде всего, семантически разные интерфейсы (если явно не определено иное). Ранее здесь в статейке вокруг "Lagoonа" на таком моменте акцентировалось -- конкретный пример со Stack -- некоторые операции с одинаковой сигнатурой, но в целом интерфейсы подразумевают разную политику стека, т.е. разную семантику (и для операций определяются разные требования/ограничения):
http://citeseerx.ist.psu.edu/viewdoc/do ... 1&type=pdf

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


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 72 ]  На страницу Пред.  1, 2, 3, 4

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2017, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB