Обсуждение:Введение, или краткий обзор

Материал из Deeptown Manual
Перейти к: навигация, поиск

Тема конфликтов расширений классов не раскрыта.

Содержание

Re

Введение потому так и называется, что оно дает общее представление и не углубляется в детали. Если хочется прочитать подробнее — читайте подробнее. И вообще, что понимаете под конфликтом? --Korvin 04:15, 25 апреля 2008 (EDT).

PS: Представьтесь пожалуйста.

Re

Там тоже не раскрыта.

В прочем раскрыть ее всеравно не получится. Ибо конфликт фундаментальный. Примерно теже проблемы возникают у системы типов Haskell'я при попытке скрестить эту систему типов с компонентностью.

А конфликт прост:

Заводим 2 модуля A и B.

В обоих модулях расширяем класс int методом GetFactorial.

Далие в модуле C пытаемся использовать модули A и B.

Внимание вопрос: GetFactorial из какого модуля использовать будем?

Особенно весело становится если все 3 модуля пишут разные люди.

Еще веселее если изначально в модуле B небыло GetFactorial, а через некоторое время появился.


Сердитый Ученый.

ЗЫ Это я еще копать не начал...

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

Re

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

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

Ну или другой вариант: другая библиотека присылает некий контейнер, который приходится использовать в текущем модуле. Но вот беда, язык на котором написан "тот" модуль понятия не имеет о замыканиях и соответственно ни о каком методе each() не знает (скажем, используется принцип search-valid-next). А нам таки хочется пользоваться всеми преимуществами примеси Enumerable. Тогда берем и расширяем класс методом each() и добавляем в родители соответствующую примесь:

extend TheirWeirdCollection extends Enumerable {
    public const function each(block b) {
        for(this.search(); this.valid(); this.next())
            b(this.current());
    }
}

И радуемся жизни:

var col = SomeMethod(); //скажем, возвращает этот самый TheirWeirdCollection 
var result = col.select() { |x| x > 5; }; //применяем примесь
result.each() { |x| puts(x); } //тут уже конечно не TheirWeirdCollection, а array

А для написания основного кода надо использовать наследование, как и положено.

ЗЫ: Сомнения дело хорошее. До тех пор, пока порождают конструктивные диалоги а не флуд и прочие холивары

--Korvin 09:52, 25 апреля 2008 (EDT)

Re

Еще раз:

Модуль А и модуль Б созданны независимыми разработчиками. Они друг о друге вобще ничего не знают.

Соответственно упорядочить модули А и Б друг относительно друга невозможно.

Они расширили один и тотже класс одним и темже методом.

Теперь третий разработчик импортировал оба модуля А и Б.

Чей метод будет использован?


Сердитый Ученый.

ЗЫ Чем дальше тем сильнее прихожу к выводу что наследование реализаций это вобще зло. Ибо очень сильно связывает систему. ИМХО можно использовать только наследование интерфейсов. Тогда система остается в управляемом состоянии гораздо дольше.

Чтобы не дублировать код можно завести 3 сущьности:

1)Интерфейс. Чистый контракт без каких либо намеков на реализацию.

2)Миксин. Может содержать код и данные. Реализует один или несколько интерфейсов. Может требовать чтобы использующий его тип реализовал один или несколько других интерфейсов нужных миксину для работы.

3)Тип. Может содержать код и данные. Может агрегировать миксины. Реализует один или несколько интерфейсов. Тип расширять нельзя. Ни наследованием ни добавление методов.

ЗЗЫ Не первый год пишу high load системы. Те куски информации что есть на вашем сайте вызывают сомнение что система вобще взлетит под хоть какойнибудь нагрузкой. Подроный анализ делать лень. Тем болие что не все подсистемы описаны.

Re

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

K++ просто ругнется ошибкой method redefinition. На этапе компиляции вся информация о методах есть.

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

--_root 11:17, 25 апреля 2008 (EDT)

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
информация
документация
Инструменты