Re[10]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 13.07.12 11:39
Оценка: 68 (3) +2 -1
Здравствуйте, Sinclair, Вы писали:

S>Моему коду нужен ICollection.


ОК.

S>Но я могу мой экземпляр ICollection передать в любой алгоритм, работающий с IEnumerable.


Пока все хорошо...

S>По-моему, это удобно.


... но потом вам этот любой алгоритм вернет IEnumerable, а вашему коду нужен ICollection. Все, приехали.

Сабтайпинг подходит для повсеместной мутабельности, когда ничего интересного не возвращают, а, в основном, на месте переписывают. Как-только начинаются какие-то заигрывания с иммутабельными "объектами" и возвращение чего-то нетривиального становится распространенным сценарием — сабтайпинг сливает со страшной силой, потому как стирает все больше информации о типах, пока не останется Top, к которому сводится все что угодно, но с которым ничего нельзя сделать. При отстутствии динамических кастов получается черная дыра, в которую легко попасть, а выбраться невозможно, а в случае их наличия — динамический глюкодром без каких-либо статических гарантий.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[6]: Зачем нужно наследование интерфейсов?
От: SV.  
Дата: 06.07.12 22:10
Оценка: 5 (2) +1
Здравствуйте, Воронков Василий, Вы писали:

>>>А я его запрещаю контрактно и сплю спокойно.

SV.>>Обобщенно говоря, если вы хотите, чтобы любой объект, поддерживающий интерфейс B, ВСЕГДА поддерживал интерфейс A

ВВ>Зачем это делать? Есть какие-то причины для этого, кроме экспериментов над людьми?

ВВ>Мне достаточно задекларировать список интерфейсов, которые я хочу получить — все.

Затем, что хороший ОО-код отражает объективную реальность, а плохой ОО-код — своего автора. В жизни есть мессенджеры, которые умеют отправлять тексты, но не умеют файлы, например, СМСный гейт, но нет таких мессенджеров, которые умеют отправлять файлы, но не умеют тексты. Мой код это отражает. Ваш — нет.
Re[5]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.07.12 13:15
Оценка: 1 (1) +2
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Неочевидно. Приведенный пример спокойно переписывается без наследования интерфейсов.


Любой пример без проблем переписывается с помощью инструкций копирования значений типа mov, сравнений и условных переходов. Давай обсудим зачем нужно что-то еще?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 06.07.12 21:51
Оценка: +3
Здравствуйте, Воронков Василий, Вы писали:

ВВ>>>Ничего не понял. Зачем мне отнаследованный интерфейс приводить к базовому да еще "безопасно"?

AVK>>Для полиморфизму.

ВВ>Можно привести пример?


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

AVK>>Странный у тебя какой то вопрос. Наследование интерфейсов ничем в плане предназначения не отличается от наследования контрактов обычных классов при наследовании классов.


ВВ>Реализация интерфейсов классами — да.


Да при чем тут реализация? Полиморфизм обеспечивается именно наследованием контрактов.

ВВ> Но сами-то интерфейсы зачем друг от друга наследовать?


Точно за тем же самым.

ВВ> В случае с классами — это хотя бы виртуальные функции и перегрузка. А с интерфейсами?


Тоже самое.

ВВ> Что дает наследование?


Безопасный апкастинг.

Мне так кажется, что ты куда то удалился совсем и не видишь очевидного. Если без интерфейсов, то ты берешь кучу разнотипных классов, выносишь общую часть в базовый класс, после чего можешь писать абстрактные алгоритмы только поверх базы.
С интерфейсами все тоже самое. Выносишь общую часть разных интерфейсов в одного предка и после этого ее можно использовать в более абстрактных алгоритмах.
Теперь что касается констрейнтов в дженериках в дотнете. Во-первых, когда проектировали интерфейсы, никаких дженериков еще не было. Во-вторых с наследованием просто писанины меньше, перечислять всю потребную кучу интерфейсов в большой иерархии может быть накладно, модифицировать при появлении еще одного интерфейса всю цепочку вызовов тоже будет весело. В-третих наследование задает готовую структуру отношений интерфейса, что удобно, повышает читабельность и накладывает дополнительные ограничения. К примеру, интерфейс IButton не имеет смысла без интерфейса IControl, поэтому проще всего его отнаследовать, и тогда любая реализация IButton будет реализовывать IControl.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[7]: Зачем нужно наследование интерфейсов?
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 07.07.12 19:18
Оценка: 2 (1) +1
ВВ>То, что вы хотите описать в рамках системы типов шарпа вообще не описывается. Потому что на самом деле та же проекция должна выглядеть так: C<E2> Map<C,E1,E2>(C<E1> seq, Func<E1,E2> fun)

не всякое C сохраняется при mapping-е. Например, упорядоченность не сохраняется.

Соответственно, для iorderedenumerable map будет другим. И такие сложные взаимосвязи едва ли можно выразить синтаксисом сильно отличающимся от перегрузки.
Re[15]: AlexRK
От: Klapaucius  
Дата: 18.07.12 08:01
Оценка: 2 (1) +1
Здравствуйте, AlexRK, Вы писали:

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


Если подумать, где еще используется сабтайпинг — то эти места очевидны. Гетерогенные списки, например. При сабтайпинге мы можем иметь массив IPet[], хранящий классы Cat и Dog. Если сабтайпинга нет — массив будет типа {exist T where T : IPet}[].
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re: Зачем нужно наследование интерфейсов?
От: mefrill Россия  
Дата: 09.07.12 13:19
Оценка: 1 (1) :)
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.

Это особенность ООП языков. Интерфейс -- понятие не ООП, а алгебраическое. Здесь
Автор(ы): Лапшин Владимир Анатольевич
В статье рассматриваются различные аспекты применения абстрактных типов данных (АТД) в программировании. Осознание концепции АТД в середине 70-х годов прошлого века повлекло за собой целый ряд работ в области теории программирования. Абстрактные типы данных на текущий момент являются одним наиболее популярных механизмов абстракции, используемым разработчиками при написании программного кода. В работе рассматриваются также основы математической теории, описывающей абстрактные типы данных как алгебраические системы. На основе сигнатур абстрактных типов данных строятся т.н. инициальные алгебры – синтаксические представления описываемых посредством АТД сущностей. Инициальные алгебры могут использоваться для верификации корректности программного кода.
я об этом пишу более подробно. Изначально, интерфейсы были придуманы, как способ программной абстракции (т.н. поведенческая абстракция). Интерфейс -- это определенный язык (словарь), посредством которого договариваются общаться с программными модулями. Абстракция здесь состоит в том, что производится отвлечение от деталей реализации языка модуля. Т.е. есть интерфейс и его реализация. При этом модули не обязательно рассматриваются как машины состояний. Наследование появилось потом, когда Лисков биологизм в программирование внесла, взяв за идеал таксономию Линнея.
Re: Зачем нужно наследование интерфейсов?
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 06.07.12 20:02
Оценка: +2
ВВ> Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.

в mainstream-языках это дает возможность статически проверять типы при возвращении интерфейса

если интерфейсы отнаследованы друг от друга
interface IEnumerable{ void Foo();}
interface ICollection:IEnumerable{void Bar();}

то функция возвращая ICollection, предоставит статически проверяемую возможность обратиться как к методам ICollection, так и к методам IEnumerable
ICollection GetItems(){..}

var items = GetItems();
items.Foo();
items.Bar();


если же интерфейсы независимы
interface IEnumerable{ void Foo();}
interface ICollection{void Bar();}

то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу

ICollection GetItems(){..}

var items = GetItem();
((IEnumerable)items).Foo();
items.Bar();
Re[13]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 17:32
Оценка: +2
Здравствуйте, AlexRK, Вы писали:

AVK>>Никому он ничего не должен. Констрейнтов явных нет — значит как повезет.


ARK>Признаться, не понимаю вопроса. Метод не возвращает нужный интерфейс IAnimal — все, это ошибка.


И? Понимаешь, если я при проектировании сразу заложил наследование IPet от IAnimal, такую ошибку в принципе нельзя сделать, компилятор не даст. Это точно такой же контроль, как и проверка соответсвия сигнатуры реализуемого метода, к примеру. Еще один уровень контроля.

AVK>>Какие средства абстрагирования ты предлагаешь взамен?


ARK>Взамен абстрагирования "изнутри"? Я писал в прошлом посте, предлагается вынести знание о создаваемом классе на тот уровень, на котором оно есть.


Ничего не понял.

AVK>>Да хоть 10 раз, проблемы это не решает. Код хоста принципиально не может знать, какая реализация будет у абстрактного контракта в конкретном плагине.


ARK>Код, использующий плагины, на определенном уровне все равно где-то обязательно знает конкретные типы.


Конечно же нет.

ARK> Такая точка должна быть. Читает из файла конфигурации названия классов, метаданные или еще что-то в этом роде.


И? Как это знание в рантайме поможет компилятору?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[11]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 17.07.12 09:43
Оценка: 16 (1)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Instance selection — статический. А наследование там есть. Вообще тему, конечно, стоило про Хаскелл создать.


Кстати, "наследование" тайпклассов в хаскеле — фича сомнительной полезности, да еще и, в некоторых случаях, достаточно проблемная.
Почему сомнительной полезности? И почему проблемная?
Члены тайпкласса "наследника" редко могут быть реализованы в терминах базового класса (тут наследование могло бы помочь), но зато очень часто базовый класс может быть реализован в терминах наследника (тут наследование ничем помочь не может). Возможно, полезность наследованию могли бы придать так называемые дефолтные реализации для суперклассов:
class Functor f => Applicative f where
    return :: x -> f x
    (<*>) :: f (s -> t) -> f s -> f t
    (>>) :: f s -> f t -> f t
    fs >> ft = return (flip const) <*> fs <*> ft
    -- описываем дефолтный инстанс для суперкласса.
    instance Functor f where
        fmap = (<*>) . return
        
class Applicative f => Monad f where
    (>>=) :: f a -> (a -> f b) -> f b
    instance Applicative f where
        ff <*> fs = ff >>= \f -> fs >>= \s -> return (f s)

В такой (гипотетической) иерархии нужно было бы реализовывать только самый "нижний" класс в иерархии из тех, что мы могли бы реализовать, получая инстансы для всей вышележащей иерархии автоматически. Проблема, думаю, понятна — пока иерархия линейна — все в порядке, но если у нас дерево — какой дефолтный инстанс из нескольких доступных предпочесть? Разумеется, это расширение не реализовано (есть правда препроцессор, который позволяет с ним поиграть.)
Без этого использовать "наследование" для повторного использования кода затруднительно.
При этом наследование обязывает определять инстансы всей иерархии, большая часть из которых по вышеописанной причине — бойлерплейт.
Принуждение к инстанциации группы классов, теоретически, может быть полезным, практика показывает, что для хаскеля это, скорее, не так. Слишком сильное связывание и все такое. Это не только мое мнение — последние ломающие изменения в base связаны с ликвидацией этой связи между классами. В той, что поставляется с ghc 7.4, убрали наследование Num от Show и Eq. В той, что будет поставляться с ghc 7.6, убрали наследование Bits от Num. При этом добавлять такие связи, наоборот, не спешат (включая и "наследование" Monad от Applicative, о котором так долго говорили большевики). Справедливости ради нужно отметить, что добавление наследования, возможно, связано с большими неприятностями с совместимостью чем удаление.

При этом, уже сейчас в хаскеле есть средства, позволяющие переиспользовать код в инстансах по максимуму без всякого наследования:
class DFunctor f where
    dmap :: (a -> b) -> f a -> f b
    default dmap :: DMonad f => (a -> b) -> f a -> f b
    dmap f = dbind (dreturn . f)
    
class DApplicative f where
    dpure :: a -> f a
    default dpure :: DMonad f => a -> f a
    dpure = dreturn
    dap :: f (a -> b) -> f a -> f b
    default dap :: DMonad f => f (a -> b) -> f a -> f b
    dap ff fs = ff `dbind` \f -> fs `dbind` \s -> dreturn (f s)

class DMonad m where
    djoin :: m(m a) -> m a
    djoin = dbind id
    
    dbind :: (a -> m b) -> m a -> m b
    default dbind :: DFunctor m => (a -> m b) -> m a -> m b
    dbind f = djoin . dmap f
    
    dreturn :: a -> m a
    default dreturn :: DApplicative m => a -> m a
    dreturn = dpure
    
-- теперь, если у нас есть инстанс DMonad, то инстансы для 
-- DFunctor и DApplicative не нужно реализовывать, только
-- указать, что они нам нужны:

instance DFunctor []
instance DApplicative []

-- Или, если есть инстансы для DFunctor и DApplicative,
-- нужно реализоватьтолько тот минимум, который добавляет DMonad:

instance DMonad [] where
    join = concat

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

Наследование, в принципе, позволяет избавиться от огромных контекстов. Но на практике для этого используется редко (городить такую сильную связь ради некоторого уменьшения писанины — спорное решение). Тем более, что в современном хаскеле есть средства куда луше:
type NumAndEq a = (Num a, Eq a)

foo :: NumAndEq a => a -> a -> Bool
foo a b = a * b == a


Т.е. в хаскеле сейчас тенденция такая: отказ от наследования в стандартных библиотеках, добавление более адекватных (это, впрочем, еще время покажет — или не покажет) средств решения проблем без всякого наследования.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[13]: AlexRK
От: Klapaucius  
Дата: 17.07.12 06:58
Оценка: 2 (1)
Здравствуйте, AlexRK, Вы писали:

ARK>Но ведь нам надо как-то инстанционировать этот сам "ящик" — он ведь будет разный в каждом плагине, раз внутри у него какой-то скрытый тип, у каждого свой. Я понимаю, что в C# подобных штук нет, но может как-нибудь на C#-подобном псевдокоде поясните?


Ну, можно попробовать:

//было IPet Get() - стало:
{exist T where T : IPet} Get()
T Get<exist T>() where T : IPet // или так
{
    // было return ((IPet) new Cat()); стало:
    return {Cat, new Cat()}; // вводим (упаковываем)
}

// так нельзя
void Foo<forall T1>(Action<T1> kill) where T1 : IPet
// нужны rank-2 типы:
void Foo(Action<forall T1> kill) where T1 : IPet
{
    var {T2, pet} = Get(); // элиминируем (распаковываем)
    // после этого биндинга можно использовать T2:
    kill<T2>(pet);
}

// но вот так нельзя:
T2 Foo(Action<forall T1> kill) where T1 : IPet
//ошибка: T2 за пределами области видимости
// так можно:
{exist T where T : IPet} Foo(Action<forall T1> kill) where T1 : IPet


Т.е. если убрать отношения сабтайпинга между классом и реализуемым им интерфейсом и оставить только интерфейсы как констрейнты — нужны экзистенциальные типы и полиморфизм ранга 2.
Если убрать наследование вообще и оставить только имплементацию интерфейсов, то диспетчеризация будет статической ("интерфейсные" вызовы можно вовсе заинлайнить) для всех универсальных (forall) типов (как сейчас для struct и интерфейсов-констрейнтов) и динамической для всех экзистенциальных (exist). Т.е. какой-то оверхед от полиморфизма останется только в тех случаях, когда без него не обойтись. Устранять же всеобщую виртуальность вызовов в тех случаях, где она не нужна (почти везде) хоть и кое-как можно, но это весьма нетривиально.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[3]: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 09.07.12 12:47
Оценка: 1 (1)
Здравствуйте, artelk, Вы писали:

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

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

_NN>>Старый вариант

_NN>>
_NN>>interface IEnumerable {}
_NN>>interface ICollection : IEnumerable {}
_NN>>interface IList : ICollection {}
_NN>>


_NN>>Новый вариант

_NN>>
_NN>>interface IEnumerable { }
_NN>>interface ICollectionPure { }
_NN>>interface IListPure { }

_NN>>alias ICollection = IEnumerable | ICollectionPure;
_NN>>alias IList = ICollectionPure | IListPure;
_NN>>


_NN>>P.S.

_NN>>Так и к структурной типизации придем

A>Нужно только, чтобы можно было объявлять поля с типами таких алиасов, возвращать их из методов и т.п.

A>И вообще:
A>
A>type ICollection = IEnumerable & ICollectionPure;

A>ICollection coll = ...;

A>IA&IB variable1 = ...;
A>IA variableA = variable1;// ~upcast

A>type IEnumerable_Or_ICollectionPure  = IEnumerable | ICollectionPure;

A>IA|IB variable3 = ...;
A>match(variable3)
A>{
A> | a is IA => ...
A> | b is IB => ...
A>}
A>//Возможно
A>variable3.F();//,если  F() есть в обоих интерфейсах (хотя тут подумать надо)

A>(IA&IB)|IC variable4 = ...;
A>


Ceylon: Principal typing, union types, and intersection types
Re[11]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.07.12 13:50
Оценка: 1 (1)
Здравствуйте, AlexRK, Вы писали:

ARK>В таком случае вашему коду нужен не ICollection, а "ICollection+IEnumerable", раз внутри него вызывается нечто, требующее IEnumerable.


Очень не многие языки умеют оперировать объединениями типов. Это прикольная концепция, но и наследование вполне решат задачи стоящие на практике.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 10.07.12 21:21
Оценка: 1 (1)
Здравствуйте, AlexRK, Вы писали:

ARK>Алиасы уже тут обсуждались, не обязательно в каждом месте.


Алиасы не спасут. Вот смотри, есть в third party библиотеке некая фабрика с методом "IPet Get()". И что ты будешь делать, если у тебя IPet от IAnimal не отнаследован? Кастить?
Наследование интерфейсов — неотъемлемая часть контракта, и современная тенденция скорее склонна контракт усложнять и делать более строгим (пре- и постусловия, инвариант и т.п.), нежели наоборот его упрощать.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[5]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 10:24
Оценка: 1 (1)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну так какую иерархию наследования ты здесь предлагаешь?


Никакую. Уж сколько лет твердили миру — иерархии идут от конкретных задач, а не из пальца. "ООП это про поведение" (С) Синклер.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[2]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 20:06
Оценка: -1
Здравствуйте, DarkGray, Вы писали:

DG>в mainstream-языках это дает возможность статически проверять типы при возвращении интерфейса

DG>если интерфейсы отнаследованы друг от друга
DG>
DG>interface IEnumerable{ void Foo();}
DG>interface ICollection:IEnumerable{void Bar();}
DG>

DG>то функция возвращая ICollection, предоставит статически проверяемую возможность обратиться как к методам ICollection, так и к методам IEnumerable
DG>
DG>ICollection GetItems(){..}
DG>var items = GetItems();
DG>items.Foo();
DG>items.Bar();
DG>

DG>если же интерфейсы независимы
DG>
DG>interface IEnumerable{ void Foo();}
DG>interface ICollection{void Bar();}
DG>

DG>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу

Что в этих мейнстрим языках уже решается через генерики

Нет, я понимаю, что "интерфейсы здесь были раньше". Т.е. если причины чисто исторические — ОК, такой ответ принимается. Вопрос, есть ли какие другие причины, кроме "а раньше мы по-другому не умели".
Re[3]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 06.07.12 20:36
Оценка: +1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ты точно понял о чем речь?


Точно понял.

ВВ> Я говорю о наследовании интерфейсов, конкретно, о возможности интерфейс наследовать от других, а не о реализации интерфейсов.


При чем тут реализация? Отнаследованный интерфейс ты можешь привести к базовому безопасно. Классический полиморфизм.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[3]: Зачем нужно наследование интерфейсов?
От: SV.  
Дата: 06.07.12 21:23
Оценка: +1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>
ВВ>interface IMessenger
ВВ>{
ВВ>    void SendMessage(string text);
ВВ>}

ВВ>interface IFileSender
ВВ>{
ВВ>    void SendFile(File file);
ВВ>}

ВВ>class SkypeMessenger : IFileSender, IMessenger;
ВВ>class SmsMessenger : IMessenger;

ВВ>...
ВВ>void SurpriseAdminInChief<T>(T messenger) where T : IFileSender, IMessenger

ВВ>void SurpriseApprenticeAdmin(IMessenger messenger)
ВВ>


...


interface IFileSenderFactory
{
    IFileSender Create();
}


...

class MyApp : Application
{
    IFileSender AdvancedMessenger
    {
        get; set;
    }
}


Каждый раз констрейнт копипакостить? Или один раз правильно контракт определить?

В любом случае, ваш код не эквивалентен моему. Вы, например, не можете отдать одну интерфейсную часть

ВВ>
ВВ>interface IMessenger
ВВ>{
ВВ>    void SendMessage(string text);
ВВ>}

ВВ>interface IFileSender
ВВ>{
ВВ>    void SendFile(File file);
ВВ>}


автору мессенджерных имплементаций и быть на 100% уверенным, что он описал SkypeMessenger именно как SkypeMessenger : IFileSender, IMessenger; — этот код на его стороне. У вас получается, что, хотя бы в принципе, кто-то может поддержать отправку файлов без текста, даже если вы такой сценарий хотите запретить. А я его запрещаю контрактно и сплю спокойно.
Re[8]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 21:51
Оценка: :)
Здравствуйте, fddima, Вы писали:

DG>>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу

ВВ>>Что в этих мейнстрим языках уже решается через генерики
F> Вто КАК это решается через генерики?

Я в третий раз уже пишу, что GetItems через генерики не реализуется, но там и интерфейс не нужен.
Re[7]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 22:17
Оценка: -1
Здравствуйте, SV., Вы писали:

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


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

Но дело даже не в этом. Я предложил подумать и высказать реальные причины, почему что-то реализовано так, а не иначе. Вы же в ответ выдали "ОО-код отражает объективную реальность". Не стоило, право, и начинать
Re[13]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 20:13
Оценка: -1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AndrewVK, Вы писали:


ВВ>>>Ну речь же про наследование.

AVK>>Речь про отмену наследования.

ВВ>Ну очевидно надо сначала разобраться, что мы решили отменять.


ВВ>>>А с ФВП ты сам прекрасно ответил на вопрос, как же возможен динамик диспатч без наследования.

AVK>>А такого вопроса никто не задавал. Вопрос был к AlexRK, как он предполагает реализовывать ДД.

ВВ>Речь идет о запрете наследования интерфейсов между собой. Реализация интерфейсов остается. Наследование классов, кстати, тоже можно убрать


Да, именно так. В какой-то момент произошла подмена понятий, что речь идет о запрете наследования вообще, причем в термин "наследование" мы также включаем и реализацию интерфейса классом. Это НЕВЕРНО.

Речь о запрете наследовать один интерфейс от другого и один класс от другого. Реализовывать интерфейс классом можно.
(Впрочем, для пущей крутизны можно интерфейс вообще не считать типом, как я выше писал.)
Re[11]: Зачем нужно наследование интерфейсов?
От: SV.  
Дата: 07.07.12 20:43
Оценка: +1
Здравствуйте, A13x, Вы писали:

A>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Здравствуйте, SV., Вы писали:


ВВ>>>>Я не знаю, что именно отражает ваш код, и какие именно мессенджеры существуют в жизни — а вы же по ходу уверены, что точно и наверняка знаете какие абстракции будут правильны в 100% случаев. Вот только в 100% эти абстракции оказываются неправильными.

SV.>>>Это бывает, да. Но для того и меню Refactor, чтобы в момент осознания несогласованности вашей объектной модели с жизнью его нажимать. И если не лениться и рефакторить код каждый раз, когда это вылезает, то да, НА ПРАКТИКЕ в 100% случаев ваши абстракции будут, как вы выразились, "правильными" (я же имел в виду их неискуственность => удобочитаемость => поддерживаемость).

A>Можно обобщить — есть набор базовых действий которые могут совершать некоторые сущности, к примеру те же мессенджеры, пример:

A>1. отправить текст
A>2. отправить файл
A>3. установить статус пользователя
A>N. ... etc.

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

A>Иными словами SkypeMessenger должен быть интерфейсом, реализующим набор базовых интерфейсов-действий из 1..N (для облегчения тестирования моками, для снижения связности, для простоты наконец для конечных потребителей этого класса).

A>Используя IoC контейнер можно ссылаться на SkypeMessenger как на несколько раздельных интерфейсов внедренных как зависимости в некоторый класс, но я не вижу никаких преимуществ у такого решения.


Читаю и охреневаю.

http://www.youtube.com/watch?v=jdwyC5HdXYk&amp;t=1m3s

Обратите внимание на мимику и страдальческую интонацию. Считайте, их я тоже процитировал.
Re: Зачем нужно наследование интерфейсов?
От: _NN_ www.nemerleweb.com
Дата: 08.07.12 08:28
Оценка: +1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.


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

Старый вариант
interface IEnumerable {}
interface ICollection : IEnumerable {}
interface IList : ICollection {}


Новый вариант
interface IEnumerable { }
interface ICollectionPure { }
interface IListPure { }

alias ICollection = IEnumerable | ICollectionPure;
alias IList = ICollectionPure | IListPure;


P.S.
Так и к структурной типизации придем
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: Зачем нужно наследование интерфейсов?
От: vdimas Россия  
Дата: 08.07.12 19:13
Оценка: +1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Неочевидно. Приведенный пример спокойно переписывается без наследования интерфейсов.


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

Предложенный способ через генерики — банально более многословен и является эмуляцией того же самомого с тем отличием, что вместо однократной декларации зависимостей ты будешь их объявлять вручную в каждом месте.
Re: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.07.12 13:26
Оценка: +1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.


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

В номинативной системе типов наследование реализует полиморфизм нужный для создания АТД и ООП.

Короче фигово троллишь .
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Зачем нужно наследование интерфейсов?
От: vpchelko  
Дата: 09.07.12 13:55
Оценка: +1
Нафиг, нужен такой полиморфизм. IPet-ом может быть не только IAnimal, но и IBird, IReptiles, IFish ...
Сало Украине, Героям Сала
Re[7]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.07.12 14:07
Оценка: -1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Может быть, стоит просто вот так написать:


ВВ>
ВВ>LazyCollection S1<T1, T2>(this LazyCollection items, Func<T1, T2> transformer)
ВВ>{
ВВ>   return new LazyCollection(items.Count, items.S1(transformer));
ВВ>}
ВВ>


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

Такие штуки прокатят только чем-то вроде классов типов, когда можно сделать по перегрузке (отдельной реализации) для каждого поддерживаемого типа.

Вот только к исходному вопросу это уже отношение не имеет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.07.12 14:21
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ARK>Вопрос не ко мне, но здесь нет никакой структурной типизации. Класс обладает теми интерфейсами, которые явно указаны. И не может реализовывать интерфейсы, только лишь получив набор методов с нужными сигнатурами.


Если нет, то это банальная логическая ошибка в рассуждениях. Ведь передается не класс, а интерфейс. А при этом информация о реализованных интерфейсах теряется. Приедется делать динамические проверки. А это уже плохо.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 09.07.12 15:41
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

Ты когда пишешь

2 + 2
12.2 + 12.2


то это ведь тоже перегрузка.
Re[11]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 09.07.12 19:06
Оценка: +1
Здравствуйте, AlexRK, Вы писали:

ВВ>>то это ведь тоже перегрузка.

ARK>Согласен. Хотя вроде бы в окамле операторы разные.

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

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


Ну каждый второй динамический язык именно такой. Один числовой тип — число. И как-то это не очень удобно.

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


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

ARK>Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


x == y ?

А, собственно, чем перегрузка функций, которая статическая, вреднее, чем динамик диспатч методов с одинаковым именем?
Re[13]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 09:37
Оценка: :)
Здравствуйте, PSV100, Вы писали:

ВВ>>Да, вот только мне лично кажется, что за громкими окамловскими лозунгами "перегрузка есть зло", скрывается банальное убожество недопиленного Хидли-Милнера.

ВВ>>В любом случае есть хороший способ проверить, каково жить без перегрузки, и посмотреть, какие припарки изобретают окамлисты, чтобы все-таки использовать одни и те же имена для разных функций.
PSV>Лично мне не нравится то, что в хаскелеподобных языках нет перегрузки по количеству аргументов в функции. Если ее ввести, то нарушится "лёгкость" карринга и будет путаница. Но можно "утяжелить" запись каррирования функций, т.е. вместо этого:

Variadic functions в той или иной степени сочетаются с каррированием. Посмотри вот, как printf в F# реализован.
А если отключить систему типов, то вполне даже неплохо сочетаются — должна быть только возможность как-либо провести зависимость между аргументами. В той же Ela такое вот прекрасно работает в сочетании с каррированными функциями:

open string

trimChars '!' '?' "!string?"
trimChars '!' "string?"


PSV>Имхо, для рядовых смертных так даже понятнее. Возможно будет некая каша, когда подчёркивание "_" есть и слева от равно (в образце при ПМ), так и справа где-то при вызове функции.


Это не каррирование. Каррирование это представление функции (a->b)->c в a->b->c. В ML/Haskell все функции уже каррированные. Ты же просто описываешь частичное применение на манер Немерле/Скала.
Я бы такое не хотел. Это куча синтаксического мусора и весь поинт-фри пойдет под кат.

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


Ну это и сейчас так есть, просто происходит автоматическая эта-экспансия.
Вообще без каррирования та же Ela резко потеряет в выразительности. Каррирование просто означает, что все функции принимают ровно один аргумент, но, так как апликация функции имеет очень высокий приоритет и лево-ассоциативна, то код вида: fun x y полностью аналогичен (fun x) y — т.е. *два* вызова функции вместо одной. Это на самом деле очень удобный трюк. Особенно, если нет необходимости типизировать функцию во время компиляции.

Я ведь, кажется, тебе приводил пример DSL-я:

test1 =
  test "Integer equality"
  given 2
    should be 2
    shouldn't be 33


Где здесь функция, и сколько она аргументов принимает? А если это все с "_" переписать?

PSV>Я не измучен функциональщиной, лишь изредка покуриваю в эту сторону. Поэтому спрашиваю как человека, познавшего хаскелестроение изнутри. Чем чреват такой "колхоз" в а-ля хаскеле ?


Чреват вырезанием combinatory style под корень.
Ну и бесскобочный вызов функций теряет всякий смысл. В общем получится Скала
Re[16]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 10.07.12 16:19
Оценка: :)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ARK>>Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

ARK>>type Int32 is Number where (value >= 0) and (value <= 2000000000);

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


Тут будет не новый тип, а alias — нужно только для того, чтобы не писать эти констрейнты в каждом методе. Тип один — Number.

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


ВВ>>>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?

ARK>>Если числовой тип один, то все будет в одном экземпляре.
ARK>>Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.

ВВ>Ну будет та же перегрузка, только в рантайме


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

ВВ>>>Да и кроме математических операторов есть вполне известные всем функции.

ARK>>Например? Читать/писать в поток?

ВВ>Нет, это пример того, как перегрузку использовать не надо.

ВВ>А вот битовые операции — также вполне известная группа функций.

Битовые операции — опять же проблема только в нескольких числовых типах...
Re[14]: Зачем нужно наследование интерфейсов?
От: hi_octane Беларусь  
Дата: 10.07.12 21:34
Оценка: :)
ВВ>И какое число знаков после запятой должно быть допустимо в идеальном языке?
Ну конечно же должны быть не убогие знаки после запятой, а абсолютно точные вычисления в обыкновенных дробях! Иначе этим идеальным язком ни один математик пользоваться не станет
Re[14]: AlexRK
От: AlexRK  
Дата: 11.07.12 13:51
Оценка: -1
Здравствуйте, artelk, Вы писали:

A>Здравствуйте, AlexRK, Вы писали:


ARK>>Здравствуйте, artelk, Вы писали:


A>>>Здравствуйте, AlexRK, Вы писали:


ARK>>Ну, можно и обратную ситуацию вообразить для наследования.

ARK>>IAnimal, IPet и IPetButNotAnimal. Это если предположить, что нам одинаково часто нужны и IPet, и IPetButNotAnimal.
A>А если IPetButNotAnimal нафиг не нужен, но его все равно придется делать, т.к. язык не поддерживает наследования?

Тут вопрос только в наименовании, так ведь? Ну да, будет кривоватый IPetOnly. Так я же и привожу обратный пример для наследования — там будет ровно та же кривизна, просто в другом случае — когда нам НУЖНЫ два интерфейса, IPet и IPetButNotAnimal.

A>>>Это все равно, что IList<T> разбить на IReadOnlyList<T> и IChangeOnlyList<T>

ARK>>Боюсь, не все равно. Кстати, такое разделение списка может быть полезным, на мой взгляд.
A>Зачем тебе может понадобится IChangeOnlyList?

Ну мало ли — кому-то может нельзя считывать содержимое, а писать можно. Например — безотносительно списка — пароли можно только записывать, а читать нельзя.
Re[9]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 17:32
Оценка: -1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Предполагает. Ибо расчитывать каждый раз на рефакторинг *интерфейсов* — это уж больно смелое допущение.


Так ты предлагаешь вообще от интерфейсов отказаться? Ну, чтобы их не рефакторить?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[9]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.07.12 00:19
Оценка: :)
Здравствуйте, Воронков Василий, Вы писали:

ВВ>И как ты себе представляешь ленивый массив?


Это к делу не относится. Мы же не о частных случаях говорим.

VD>>Такие штуки прокатят только чем-то вроде классов типов, когда можно сделать по перегрузке (отдельной реализации) для каждого поддерживаемого типа.

VD>>Вот только к исходному вопросу это уже отношение не имеет.

ВВ>Какие такие штуки? Причем тут классы?


Ты точно понял, что я тебе написал? Попробуй прочесть еще раз.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[19]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 18.07.12 08:01
Оценка: +1
Здравствуйте, AndrewVK, Вы писали:

AVK>Гибриды. Т.е. языки с полноценной поддержкой и ООП и ФЯ.


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

AVK>Типа Scala или Kotlin.


Полноценной поддержки ФЯ в них и близко нет. Хотя создатели первого языка стараются изо всех сил. И уровень поддержки в них — несравнимый. В Scala приближается к ML с нормальными модулями (снизу), в Kotlin приближается к уровню C# (сверху). Попытка написать на скале что-то в ФЯ-стиле приводит к коду, по изяществу сопоставимому с упражнениями Александреску (см. Scalaz), кроме того, идиоматический ФП-код на скале адски тормозит. Создатели второго — даже и не стараются.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[19]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 18.07.12 08:20
Оценка: +1
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Мне кажется, тут следует вначале задать другой вопрос — а что *нужно* мейнстриму?


Мейнстриму нужны инструменты решения задач, на которые есть спрос.

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


"Доменный" язык — это просто библиотека с удобным интерфейсом. Нужны будут средства для их разработки.

ВВ>Т.о. программирование превращается скорее в этакую "конфигурацию" софта. Тенденция такая, однако, намечается.


В этом ничего нового нет. Многие задачи, которые сейчас решаются "конфигурацией софта" — раньше решались программистами. Но мейнстрим не стал конфигурацией софта, т.е. не перестал быть программированием. Просто мейнстрим стал решать другие проблемы. А когда и они начнут решаться конфигурацией софта — все еще будет решать другие. Задач для программистов меньше не станет.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 13:27
Оценка:
Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.
Re: Зачем нужно наследование интерфейсов?
От: о_О
Дата: 06.07.12 13:34
Оценка:
  тоже, что и наследование неинтерфейсов
struct IAnimal
{
   virtual ~IAnimal() { }

   virtual unsigned GetAge() = 0;
};

struct IPet : virtual IAnimal
{
   virtual unsigned GetOwnerAge() = 0;
};

/*************************************************************************************************/

struct Animal : virtual public IAnimal
{
   unsigned GetAge() override
   {
      return _age;
   }

private:
   unsigned _age;
};

struct Pet : virtual public IPet, public Animal
{
   unsigned GetOwnerAge() override
   {
      return _ownerAge;
   }

private:
   unsigned _ownerAge;
};
Re[2]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 13:40
Оценка:
Здравствуйте, о_О, Вы писали:

А зачем IPet наследовать от IAnimal? Что вам это дает?
Re: Зачем нужно наследование интерфейсов?
От: Temoto  
Дата: 06.07.12 13:41
Оценка:
ВВ>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.

Как и многие фичи, эту можно отнести к удобству изменения кода.

interface ByteReader {
  func Read(buffer byte[], length uint64) (read uint64)
}

interface ByteWriter ...

interface File {
  ByteReader
  ByteWriter
  open,close...
}

interface NetworkConnection {
  ByteReader
  ByteWriter
  bind,connect...


Потом вспоминаем, что при чтении бывают ошибки, меняем сигнатуру ByteReader/Writer, изменения автоматически расползлись по всем унаследованным интерфейсам.
Re[2]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 16:44
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Как и многие фичи, эту можно отнести к удобству изменения кода.

T>
T>interface ByteReader {
T>  func Read(buffer byte[], length uint64) (read uint64)
T>}
T>interface ByteWriter ...
T>interface File {
T>  ByteReader
T>  ByteWriter
T>  open,close...
T>}
T>interface NetworkConnection {
T>  ByteReader
T>  ByteWriter
T>  bind,connect...
T>

T>Потом вспоминаем, что при чтении бывают ошибки, меняем сигнатуру ByteReader/Writer, изменения автоматически расползлись по всем унаследованным интерфейсам.

Честно, я не понял пример. File наследуется от ByteReader/ByteWriter? Как-то это... странно

Ну положим, эта цепочка наследования валидна. Мне здесь непонятно две вещи:

1) Как это помогает автоматическом "расползанию" изменений? Сейчас у тебя некий метод работает с абстракцией IFile. Без наследования он будет работать с абстракцией (IByteReader IByteWriter IFile) — если ему действительно нужно все это барахло. Ну и в чем профит?

2) А вот проблему потенциальную я вижу. Интерфейсы закрыты, и если IFile писали не мы, то отнаследовать его от IByteReader ты уже не сможешь. Поэтому в таком случае ты просто создашь отдельный интерфейс IByteReader — и дальше см. п. 1. В тех случаях, когда ты пишешь все сам, ты-таки отнаследуешь. И итоговая картина получается какой-то... несимметричной.
Re[3]: Зачем нужно наследование интерфейсов?
От: Temoto  
Дата: 06.07.12 18:46
Оценка:
ВВ>Честно, я не понял пример. File наследуется от ByteReader/ByteWriter? Как-то это... странно

ВВ>Ну положим, эта цепочка наследования валидна. Мне здесь непонятно две вещи:


ВВ>1) Как это помогает автоматическом "расползанию" изменений? Сейчас у тебя некий метод работает с абстракцией IFile. Без наследования он будет работать с абстракцией (IByteReader IByteWriter IFile) — если ему действительно нужно все это барахло. Ну и в чем профит?


Как это помогает: меняем интерфейс Reader, автомагически изменился File и NetworkConnection. Вот такое свойство данной системы типов. Ничего ни с чем не сравниваю и не предлагаю.

Если система типов позволяет функции open вернуть безымянное объединение интерфейсов ByteReader+Writer+File — это круто. Я пока такого не видел, видел только возможность вернуть один именованый тип.

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


Отнаследовать существующий тип — эту фразу я вообще не понимаю. Мне логично любой чужой тип рассматривать как неизменяемый.
Re[4]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 18:57
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Как это помогает: меняем интерфейс Reader, автомагически изменился File и NetworkConnection. Вот такое свойство данной системы типов. Ничего ни с чем не сравниваю и не предлагаю.


Ну мы же рассматриваем это с позиции нужно/не нужно. Вот зачем автоматически менять *интерфейсы* File и NetworkConnection? Сами же эти интерфейсы не поменялись. По-моему это вообще скорее плохо.

T>Если система типов позволяет функции open вернуть безымянное объединение интерфейсов ByteReader+Writer+File — это круто. Я пока такого не видел, видел только возможность вернуть один именованый тип.


Как это не видел? В том же шарпе да и джаве это делается через генерики легко и просто. Причем это языки с не самой навороченной системой типов.

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

T>Отнаследовать существующий тип — эту фразу я вообще не понимаю. Мне логично любой чужой тип рассматривать как неизменяемый.

А чего тут понимать-то? Вот забыли разработчики какой-нибудь библиотеки добавить нужную тебе абстракцию. Скажем, интерфейс ICollection сделали, а вот какой-нибудь IMeasurable(Count) не сделали. Если бы ты писал с нуля, то отнаследовал бы ICollection от IMeasurable, а так не получится — придется довольствоваться двумя несвязанными интерфейсами. И такие ситуации — сплошь и рядом.
Re[4]: Зачем нужно наследование интерфейсов?
От: RomikT Германия  
Дата: 06.07.12 19:10
Оценка:
Здравствуйте, Temoto, Вы писали:

T>Если система типов позволяет функции open вернуть безымянное объединение интерфейсов ByteReader+Writer+File — это круто. Я пока такого не видел, видел только возможность вернуть один именованый тип.


В Scala можно:
trait A { def foo: String }
trait B { def bar: String }

def getIt: A with B =
  new A with B {
    def foo = "hello"
    def bar = "world"
  }
Думаю, она в этом плане не уникальна.
Re[5]: Зачем нужно наследование интерфейсов?
От: Temoto  
Дата: 06.07.12 19:16
Оценка:
T>>Если система типов позволяет функции open вернуть безымянное объединение интерфейсов ByteReader+Writer+File — это круто. Я пока такого не видел, видел только возможность вернуть один именованый тип.

ВВ>Как это не видел? В том же шарпе да и джаве это делается через генерики легко и просто. Причем это языки с не самой навороченной системой типов.


Можно пример?

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

T>>Отнаследовать существующий тип — эту фразу я вообще не понимаю. Мне логично любой чужой тип рассматривать как неизменяемый.

ВВ>А чего тут понимать-то? Вот забыли разработчики какой-нибудь библиотеки добавить нужную тебе абстракцию. Скажем, интерфейс ICollection сделали, а вот какой-нибудь IMeasurable(Count) не сделали. Если бы ты писал с нуля, то отнаследовал бы ICollection от IMeasurable, а так не получится — придется довольствоваться двумя несвязанными интерфейсами. И такие ситуации — сплошь и рядом.


Ты хочешь рассматривать открытые типы, когда я могу в чужую коллекцию добавить свою реализацию Count? Если нет, то я не понимаю почему речь идёт о чужом коде. Чужой код для меня закрыт, он обладает или не обладает нужными интерфейсами, но это невозможно изменить.
Re: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 06.07.12 19:22
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Собственно, сабж. Что это дает-то в принципе?


Полиморфизм это дает. Который, в свою очередь, решает задачу динамической диспетчеризации по типу аргумента.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[2]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 19:41
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, Воронков Василий, Вы писали:

ВВ>>Собственно, сабж. Что это дает-то в принципе?
AVK>Полиморфизм это дает. Который, в свою очередь, решает задачу динамической диспетчеризации по типу аргумента.

Ты точно понял о чем речь? Я говорю о наследовании интерфейсов, конкретно, о возможности интерфейс наследовать от других, а не о реализации интерфейсов.
Re[6]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 19:58
Оценка:
Здравствуйте, Temoto, Вы писали:

ВВ>>Как это не видел? В том же шарпе да и джаве это делается через генерики легко и просто. Причем это языки с не самой навороченной системой типов.

T>Можно пример?

C#:

T Something<T>(T val) where T : IFoo, IBar
{
  ...
}


ВВ>>А чего тут понимать-то? Вот забыли разработчики какой-нибудь библиотеки добавить нужную тебе абстракцию. Скажем, интерфейс ICollection сделали, а вот какой-нибудь IMeasurable(Count) не сделали. Если бы ты писал с нуля, то отнаследовал бы ICollection от IMeasurable, а так не получится — придется довольствоваться двумя несвязанными интерфейсами. И такие ситуации — сплошь и рядом.

T>Ты хочешь рассматривать открытые типы, когда я могу в чужую коллекцию добавить свою реализацию Count?

Нет, не хочу.

T>Если нет, то я не понимаю почему речь идёт о чужом коде. Чужой код для меня закрыт, он обладает или не обладает нужными интерфейсами, но это невозможно изменить.


Ты пользуешься исключительно своими интерфейсами, которые сам же и пишешь? "Чужой код" может предоставлять не только реализации, но также и абстракции, которыми ты можешь пользоваться. А зачастую — которыми ты вынужден пользоваться. В абстракциях же часто присутствуют "дыры". Возможность наследования интерфейсов создает некие иерархии, в которые нельзя вклиниваться, если на каком-то уровне пропущена нужная тебе абстракция. Вот и приходится навешивать эти абстракции "снаружи".
Re[3]: Зачем нужно наследование интерфейсов?
От: fddima  
Дата: 06.07.12 20:17
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

DG>>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу

ВВ>Что в этих мейнстрим языках уже решается через генерики
Как это решается через генерики?
Re[4]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 20:25
Оценка:
Здравствуйте, fddima, Вы писали:

DG>>>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу

ВВ>>Что в этих мейнстрим языках уже решается через генерики
F> Как это решается через генерики?

GetItems? Там вообще непонятно, зачем возвращать интерфейс. Это же не полиморфный метод, он вполне конкретную штуку возвращает. Если метод полиморфный, то нужные интерфейсы просто навешиваются в констрейнтах.
Re[4]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 20:46
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ВВ>> Я говорю о наследовании интерфейсов, конкретно, о возможности интерфейс наследовать от других, а не о реализации интерфейсов.

AVK>При чем тут реализация? Отнаследованный интерфейс ты можешь привести к базовому безопасно. Классический полиморфизм.

Ничего не понял. Зачем мне отнаследованный интерфейс приводить к базовому да еще "безопасно"? Зачем мне вообще приводить интерфейс к чему-либо?
Re: Зачем нужно наследование интерфейсов?
От: SV.  
Дата: 06.07.12 20:53
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.



// Any protocol supports plain text.
interface IMessenger
{
    void SendMessage(string text);
}

// No protocols support file transport only. If there is one, the contract is not valid anymore.
interface IFileSender : IMessenger
{
    void SendFile(File file);
}

class SkypeMessenger : IFileSender; // It's easy to support both text and file sending via Skype.
class SmsMessenger : IMessenger; // ...But not via SMS.

class MyApp : Application
{
...
void SurpriseAdminInChief(IFileSender messenger)
{
    messenger.SendFile(_dumpFile);
    messenger.SendText(_criticalErrorMessage); // We are absolutely sure we can send text if we can send files.
}
void SurpriseApprenticeAdmin(IMessenger messenger)
{
    messenger.SendText(_warningMessage);
}
...
}
Re[2]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 21:01
Оценка:
Здравствуйте, SV., Вы писали:

interface IMessenger
{
    void SendMessage(string text);
}

interface IFileSender
{
    void SendFile(File file);
}

class SkypeMessenger : IFileSender, IMessenger;
class SmsMessenger : IMessenger;

...
void SurpriseAdminInChief<T>(T messenger) where T : IFileSender, IMessenger

void SurpriseApprenticeAdmin(IMessenger messenger)
Re[5]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 06.07.12 21:12
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ничего не понял. Зачем мне отнаследованный интерфейс приводить к базовому да еще "безопасно"?


Для полиморфизму.

ВВ> Зачем мне вообще приводить интерфейс к чему-либо?


Аналогично.

Странный у тебя какой то вопрос. Наследование интерфейсов ничем в плане предназначения не отличается от наследования контрактов обычных классов при наследовании классов.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re: Зачем нужно наследование интерфейсов?
От: b-3 Россия  
Дата: 06.07.12 21:20
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.


Наследование вообще вредно, а наследование интерфейсов выявляет наиболее неприятные черты этого приёма.

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

если же наследование интерфейса не выражает отношение абстракции — к примеру, как тут говорили: "нужно добавить метод — давайте из IFoo сделаем IFoo2" — тут уже идёт один вред для архитектуры.
Забанен с формулировкой "клинический дисидент".
Re[6]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 21:25
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ВВ>>Ничего не понял. Зачем мне отнаследованный интерфейс приводить к базовому да еще "безопасно"?

AVK>Для полиморфизму.

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

ВВ>> Зачем мне вообще приводить интерфейс к чему-либо?

AVK>Аналогично.
AVK>Странный у тебя какой то вопрос. Наследование интерфейсов ничем в плане предназначения не отличается от наследования контрактов обычных классов при наследовании классов.

Реализация интерфейсов классами — да. Но сами-то интерфейсы зачем друг от друга наследовать? В случае с классами — это хотя бы виртуальные функции и перегрузка. А с интерфейсами? Что дает наследование?
Re[2]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 21:27
Оценка:
Здравствуйте, b-3, Вы писали:

b-3>И всё же без него нельзя обойтись, т.к. это единственный способ (в mainstream, во всяком случае) выразить средствами языка отношение "общее-частность".


Почему единственное? Интерфейс — всегда общее. Реализация — всегда частность. Понятно, что из интерфейсов можно построить некую иерархию, но зачем? Можно просто разобрать эту иерархию, и все будет работать точно так же. Собственно, зачем интерфейсы по отношению друг к другу должны находиться в отношении "общее-частностность"? Что это дает?
Re[4]: Зачем нужно наследование интерфейсов?
От: SV.  
Дата: 06.07.12 21:36
Оценка:
Здравствуйте, SV., Вы писали:

>А я его запрещаю контрактно и сплю спокойно.


Обобщенно говоря, если вы хотите, чтобы любой объект, поддерживающий интерфейс B, ВСЕГДА поддерживал интерфейс A (в частности, но не только, обязать имплементатора интерфейса B имплементировать интерфейс A), вам нужно наследование B от A. Если такой потребности нет, наследование интерфейсов не нужно, вредно и так далее.
Re[4]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 21:39
Оценка:
Здравствуйте, SV., Вы писали:

SV.>
SV.>class MyApp : Application
SV.>{
SV.>    IFileSender AdvancedMessenger
SV.>    {
SV.>        get; set;
SV.>    }
SV.>}
SV.>


SV.>Каждый раз констрейнт копипакостить? Или один раз правильно контракт определить?


Что вы собрались копипастить? AdvancedMessenger — это конкретный неполиморфный метод, который вполне может возвращать конкретную реализацию.

SV.>В любом случае, ваш код не эквивалентен моему. Вы, например, не можете отдать одну интерфейсную часть

SV.>автору мессенджерных имплементаций и быть на 100% уверенным, что он описал SkypeMessenger именно как SkypeMessenger : IFileSender, IMessenger; — этот код на его стороне. У вас получается, что, хотя бы в принципе, кто-то может поддержать отправку файлов без текста, даже если вы такой сценарий хотите запретить. А я его запрещаю контрактно и сплю спокойно.

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

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

А вам ведь на самом деле нужно было всего лишь это:

interface IMessenger<T> where T : IMessage
{
   void Send(T);
}
Re[5]: Зачем нужно наследование интерфейсов?
От: fddima  
Дата: 06.07.12 21:43
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

DG>>>>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу

ВВ>>>Что в этих мейнстрим языках уже решается через генерики
F>> Как это решается через генерики?
ВВ>GetItems? Там вообще непонятно, зачем возвращать интерфейс. Это же не полиморфный метод, он вполне конкретную штуку возвращает. Если метод полиморфный, то нужные интерфейсы просто навешиваются в констрейнтах.
Уффф. Нет, что-то я в GetItems не вижу генериков... Или слепой или не знаю. Можно как-то по человечески объяснить, что имеется ввиду? Пожалуйста.
Re[6]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 21:47
Оценка:
Здравствуйте, fddima, Вы писали:

DG>>>>>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу

ВВ>>>>Что в этих мейнстрим языках уже решается через генерики
F>>> Как это решается через генерики?
ВВ>>GetItems? Там вообще непонятно, зачем возвращать интерфейс. Это же не полиморфный метод, он вполне конкретную штуку возвращает. Если метод полиморфный, то нужные интерфейсы просто навешиваются в констрейнтах.
F> Уффф. Нет, что-то я в GetItems не вижу генериков... Или слепой или не знаю. Можно как-то по человечески объяснить, что имеется ввиду? Пожалуйста.

GetItems — это в примере неполиморфный метод. Возвращайте конкретный тип.

Или уж слепите класс. ICollection — это вообще по сути скорее single inheritance класс, а не интерфейс.
Re[5]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 21:49
Оценка:
Здравствуйте, SV., Вы писали:

SV.>Здравствуйте, SV., Вы писали:

>>А я его запрещаю контрактно и сплю спокойно.
SV.>Обобщенно говоря, если вы хотите, чтобы любой объект, поддерживающий интерфейс B, ВСЕГДА поддерживал интерфейс A

Зачем это делать? Есть какие-то причины для этого, кроме экспериментов над людьми?
Мне достаточно задекларировать список интерфейсов, которые я хочу получить — все.
Re[7]: Зачем нужно наследование интерфейсов?
От: fddima  
Дата: 06.07.12 21:49
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>GetItems — это в примере неполиморфный метод. Возвращайте конкретный тип.

ВВ>Или уж слепите класс. ICollection — это вообще по сути скорее single inheritance класс, а не интерфейс.
Ок, откатимся назад.

DG>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу

ВВ>Что в этих мейнстрим языках уже решается через генерики
Вто КАК это решается через генерики?
Re[3]: Зачем нужно наследование интерфейсов?
От: vdimas Россия  
Дата: 06.07.12 21:54
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>А зачем IPet наследовать от IAnimal? Что вам это дает?


То же, что любой другой рантайм-полиморфизм.
Re[5]: Зачем нужно наследование интерфейсов?
От: SV.  
Дата: 06.07.12 21:59
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


И это ОЧЕНЬ хорошо, поскольку когда клиент вашего кода вызовет не нужный ВАМ, но нужный ЕМУ метод, и метод выкинет NotImplementedException, то долго не придется искать, кого бить по наглой рыжей морде. Что касается нужности, все наоборот: контрактную часть описывает архитектор системы, а "орлы" ее реализуют. И не дело "орлов" принимать решения на уровне архитектуры, по крайней мере, не посоветовавшись с остальными.

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


ВВ>А вам ведь на самом деле нужно было всего лишь это:


ВВ>
ВВ>interface IMessenger<T> where T : IMessage
ВВ>{
ВВ>   void Send(T);
ВВ>}
ВВ>


Как с архитектором я бы с вами работать не стал. Интерфейсы должны быть кристально прозрачны, и служить документацией. Из моего интерфейсного кода понятно, что есть объекты, некоторые из которых умеют отправлять только текст, а другие — и текст, и файлы, но нет таких, которые умеют отправлять только файлы. Мессенджер, текст, файл — понятия из реальной жизни, поэтому код читается как азбука. В вашем коде и текст, и файл зачем-то обобщаются до абстрактного "сообщения". Отправляя тексты и файлы через скайп, вы в самом деле держите в уме, что и то, и другое — по сути одно и то же, некоторое "сообщение"? Или вы отправляете тексты и файлы?
Re[8]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 22:01
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ВВ>>>>Ничего не понял. Зачем мне отнаследованный интерфейс приводить к базовому да еще "безопасно"?

AVK>>>Для полиморфизму.
ВВ>>Можно привести пример?
AVK>Пример полиморфизма на наследовании?

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

Я не понимаю, зачем мне приводить интерфейсы, и как это помогает полиморфизму.

AVK>>>Странный у тебя какой то вопрос. Наследование интерфейсов ничем в плане предназначения не отличается от наследования контрактов обычных классов при наследовании классов.

ВВ>>Реализация интерфейсов классами — да.
AVK>Да при чем тут реализация? Полиморфизм обеспечивается именно наследованием контрактов.

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

ВВ>> Что дает наследование?

AVK>Безопасный апкастинг.

А зачем мне нужен этот апкастинг? В каких случаях он используется?

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

AVK>С интерфейсами все тоже самое. Выносишь общую часть разных интерфейсов в одного предка и после этого ее можно использовать в более абстрактных алгоритмах.
AVK>Теперь что касается констрейнтов в дженериках в дотнете. Во-первых, когда проектировали интерфейсы, никаких дженериков еще не было. Во-вторых с наследованием просто писанины меньше, перечислять всю потребную кучу интерфейсов в большой иерархии может быть накладно, модифицировать при появлении еще одного интерфейса всю цепочку вызовов тоже будет весело. В-третих наследование задает готовую структуру отношений интерфейса, что удобно, повышает читабельность и накладывает дополнительные ограничения. К примеру, интерфейс IButton не имеет смысла без интерфейса IControl, поэтому проще всего его отнаследовать, и тогда любая реализация IButton будет реализовывать IControl.

IButton, IControl — вообще какие-то странные интерфейсы. Ну да ладно.
Положим, они бы не были отнаследованы. И что, какая проблема с этим? Мы что-то важное потеряем в результате?
Re[4]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 22:03
Оценка:
Здравствуйте, vdimas, Вы писали:

ВВ>>А зачем IPet наследовать от IAnimal? Что вам это дает?

V>То же, что любой другой рантайм-полиморфизм.

Неочевидно. Приведенный пример спокойно переписывается без наследования интерфейсов.
Re[6]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 06.07.12 22:09
Оценка:
Здравствуйте, SV., Вы писали:

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

SV.>И это ОЧЕНЬ хорошо, поскольку когда клиент вашего кода вызовет не нужный ВАМ, но нужный ЕМУ метод, и метод выкинет NotImplementedException, то долго не придется искать, кого бить по наглой рыжей морде. Что касается нужности, все наоборот: контрактную часть описывает архитектор системы, а "орлы" ее реализуют. И не дело "орлов" принимать решения на уровне архитектуры, по крайней мере, не посоветовавшись с остальными.

Ничего не понял. В моем случае как раз никто не получит по морде. Потому что клиент моего кода явно задекларирует те интерфейсы, которые ему ДЕЙСТВИТЕЛЬНО нужны, а не получит бомбу с NotImplementedException.

SV.>Как с архитектором я бы с вами работать не стал.


ОК, если у нас откроются вакансии, то я вас не позову.

SV.>Интерфейсы должны быть кристально прозрачны, и служить документацией. Из моего интерфейсного кода понятно, что есть объекты, некоторые из которых умеют отправлять только текст, а другие — и текст, и файлы, но нет таких, которые умеют отправлять только файлы. Мессенджер, текст, файл — понятия из реальной жизни, поэтому код читается как азбука. В вашем коде и текст, и файл зачем-то обобщаются до абстрактного "сообщения". Отправляя тексты и файлы через скайп, вы в самом деле держите в уме, что и то, и другое — по сути одно и то же, некоторое "сообщение"? Или вы отправляете тексты и файлы?


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

В моем варианте "документацией" служат именно те интерфейсы, которые и должны служить документацией в данном случае — контракты сообщений. А скайп или СМС — это, вообще говоря, "абстракции" уже другого уровня.
Re[7]: Зачем нужно наследование интерфейсов?
От: SV.  
Дата: 06.07.12 22:29
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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

SV.>>И это ОЧЕНЬ хорошо, поскольку когда клиент вашего кода вызовет не нужный ВАМ, но нужный ЕМУ метод, и метод выкинет NotImplementedException, то долго не придется искать, кого бить по наглой рыжей морде. Что касается нужности, все наоборот: контрактную часть описывает архитектор системы, а "орлы" ее реализуют. И не дело "орлов" принимать решения на уровне архитектуры, по крайней мере, не посоветовавшись с остальными.

ВВ>Ничего не понял. В моем случае как раз никто не получит по морде. Потому что клиент моего кода явно задекларирует те интерфейсы, которые ему ДЕЙСТВИТЕЛЬНО нужны, а не получит бомбу с NotImplementedException.


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

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

  Скрытый текст


Что делать этому третьему, когда вы ему вернете мессенджер, в котором по каким-то своим причинам ЯВНО не стали поддерживать отправку текста, а его клиенты столь же ЯВНО требуют избегать таких ситуаций? Особенно замечательно будет, когда этот третий — приложение, которое пишется раньше всего, а первые два — плагины. Что делать автору приложения? Вот он и вводит КОНТРАКТЫ, которые остальные должны соблюдать, если не хотят по наглой рыжей морде.

SV.>>Как с архитектором я бы с вами работать не стал.

ВВ>ОК, если у нас откроются вакансии, то я вас не позову.

Возьмите хотя бы чай подавать А еще я козликом вышиваю. И это самое... мастер. На фендер-стратокастер.
Re[8]: Зачем нужно наследование интерфейсов?
От: SV.  
Дата: 06.07.12 22:52
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


ВВ>Я не знаю, что именно отражает ваш код, и какие именно мессенджеры существуют в жизни — а вы же по ходу уверены, что точно и наверняка знаете какие абстракции будут правильны в 100% случаев. Вот только в 100% эти абстракции оказываются неправильными.


Это бывает, да. Но для того и меню Refactor, чтобы в момент осознания несогласованности вашей объектной модели с жизнью его нажимать. И если не лениться и рефакторить код каждый раз, когда это вылезает, то да, НА ПРАКТИКЕ в 100% случаев ваши абстракции будут, как вы выразились, "правильными" (я же имел в виду их неискуственность => удобочитаемость => поддерживаемость).

В первоначальном примере у меня как раз рассматривался случай, когда появляется какой-нибудь DropBoxClient, контракт становится невалидным, его переписывают и компилятор показывает все вытекающие из этого ошибки. Для простоты я его стер. Зря, наверное.

>Потому что ОО код никакого отношения к объективной реальности не имеет.


Чем меньше не имеет, тем хуже (его читателям).

ВВ>Но дело даже не в этом. Я предложил подумать и высказать реальные причины, почему что-то реализовано так, а не иначе. Вы же в ответ выдали "ОО-код отражает объективную реальность". Не стоило, право, и начинать


Я привел конкретный пример и, как мог, объяснил, почему он... нет, не реализован, а ЗАПРОЕКТИРОВАН так, а не иначе. В том-то и дело, что реализовать всегда можно хоть так, хоть иначе, и все будет работать. Теперь я понимаю, почему вы не понимаете наследование интерфейсов. Оно не вам нужно, а тому, кто ваш код будет читать, править, развивать, фиксить баги, строить на его основе плагины и так далее.

Хотите голосовалку создам, с вашим интерфейсом и моим? И пусть vox populi скажет, с чьей ОМ ему работать больше по душе. Ставки УЖЕ сделаны, оба интерфейсных куска кода написаны, все ходы записаны.
Re[3]: Зачем нужно наследование интерфейсов?
От: b-3 Россия  
Дата: 06.07.12 23:00
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, b-3, Вы писали:


b-3>>И всё же без него нельзя обойтись, т.к. это единственный способ (в mainstream, во всяком случае) выразить средствами языка отношение "общее-частность".


ВВ>Почему единственное? Интерфейс — всегда общее. Реализация — всегда частность. Понятно, что из интерфейсов можно построить некую иерархию, но зачем? Можно просто разобрать эту иерархию, и все будет работать точно так же. Собственно, зачем интерфейсы по отношению друг к другу должны находиться в отношении "общее-частностность"? Что это дает?


Это даёт проверку отношения "общее-частность" компилятором и IDE. "Разобрали" иерархию — только на тестирование можно надеяться. Минус бонусы в виде рефакторинга, минус оптимизация по скорости.

А ещё, в коде появится куча неприятных мест, где объект получаем по одному интерфейсу, якобы частному, а затем динамически приводим к "другому", который "общий"... вернее, раньше был "общим", но там появился эээ нюанс — да бог с ним! с молитвой так сказать. Почему вообще наобум приводим? Да потому что костыли, потому что разные разработчики у разных кусков кода, а ещё какой-то вася влепил IMyInterface2 в целях расширения, а ещё у нас сплошной TDD при выключённом мозге... И будет проверка в рантайме. И падения в таких местах у вас будут вылезать как Access Violation в программе на Delphi — вроде можно их все отловить, а что-то никак не получается

Конкретно в шарпе ещё можно нарваться на ошибку, когда IBase.Foo() — это одна реализация, а IChild.Foo() — другая. Вам будет очень весело ловить баг, когда вы "разобрали иерархию", а кто-то воткнул два одноимённых метода.

З.Ы. Я вполне осознаю, что и с наследованием можно аналогично влететь, потому что компилятор контракт интерфейса всё равно полностью не проверяет... но шансов меньше. Тут принцип один — максимально верифицировать код и статикой (типизация, code contracts), и тестированием. Грубо говоря, дублирование вместо наследования оправдано только в том случае, если оно резко сокращает объём юнит-тестов. Даже не реальных тестов, а воображаемого "полного набора тестов", проверяющего без халтуры все-все требования к коду.
А ещё бывает, что дублирование интерфейсов оправдано моделью версионирования/форматом выпуска ПО.
Забанен с формулировкой "клинический дисидент".
Re[7]: Зачем нужно наследование интерфейсов?
От: vdimas Россия  
Дата: 06.07.12 23:36
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Реализация интерфейсов классами — да. Но сами-то интерфейсы зачем друг от друга наследовать? В случае с классами — это хотя бы виртуальные функции и перегрузка. А с интерфейсами? Что дает наследование?


Это и есть полиморфизм на наследовании и виртуальных методах. Вполне может быть иерархия интерфейсов, ортогональная иерархии реализующих их классов. Для чего вообще нужны иерархии? Для распределения функциональности. Вот на каждом уровне иерархии своя функциональность — от общей к частной.
Re[6]: Зачем нужно наследование интерфейсов?
От: vdimas Россия  
Дата: 06.07.12 23:41
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Зачем это делать? Есть какие-то причины для этого, кроме экспериментов над людьми?

ВВ>Мне достаточно задекларировать список интерфейсов, которые я хочу получить — все.

Это для одного генерика. А если у нас абстрактные алгоритмы для многих генериков? А если возникает ситуация, когда генерик определяет базовый класс? Ведь так нельзя.
Re[9]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 09:09
Оценка:
Здравствуйте, SV., Вы писали:

ВВ>>Я не знаю, что именно отражает ваш код, и какие именно мессенджеры существуют в жизни — а вы же по ходу уверены, что точно и наверняка знаете какие абстракции будут правильны в 100% случаев. Вот только в 100% эти абстракции оказываются неправильными.

SV.>Это бывает, да. Но для того и меню Refactor, чтобы в момент осознания несогласованности вашей объектной модели с жизнью его нажимать. И если не лениться и рефакторить код каждый раз, когда это вылезает, то да, НА ПРАКТИКЕ в 100% случаев ваши абстракции будут, как вы выразились, "правильными" (я же имел в виду их неискуственность => удобочитаемость => поддерживаемость).

Вы предлагаете рефакторить код, каждый раз когда меняются требования? Что-то я не улавливаю суть. А если нельзя рефакторить, и код уже в продакшине? Вообще такая роскошь как рефактор *интерфейсов* далеко не всегда доступна. Закладываться на это при дизайне — я бы лично не стал.
Может, стоит подойти с другого конца и постараться сделать код более устойчивым к изменениям? Например, не делать предположений — "все мессенджеры, умеющие отсылать файлы, должны уметь отсылать текст". Меня пугает такой постулат, вводимый на уровне дизайна. Более того, непонятно, что он дает.

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

SV.>В первоначальном примере у меня как раз рассматривался случай, когда появляется какой-нибудь DropBoxClient, контракт становится невалидным, его переписывают и компилятор показывает все вытекающие из этого ошибки. Для простоты я его стер. Зря, наверное.


Неудивительно, что вы его стерли. Он же ломает вашу абстракцию.

>>Потому что ОО код никакого отношения к объективной реальности не имеет.

SV.>Чем меньше не имеет, тем хуже (его читателям).

Нет никакой объективной реальности.
Есть люди, которые придумывают "что" должно быть.
Есть люди, которые придумывают "как" это должно быть реализовано.
И это — разные люди.

В первой итерации проекта вам сказали — у нас есть мессенджер. Вы решили — мессенджер это что-то "типа скайпа". Во второй итерации оказалось, что дропбокс — это тоже внезапно мессенджер. Но в вашу систему абстракций это не вписывается. Рефакторить? Но ведь код уже в продакшине.

На самом деле в отношении любого программного обеспечения можно сделать два утверждения:
1) Наш код содержит ошибки
2) Наши абстракции неправильные
Ведь 1) это же банальность, правда? Вы же не будете разрабатывать программную систему исходя из "давайте сделаем так, чтобы была 100% гарантия отсутствия ошибок". Это невозможно. Правильнее думать в другом направлении — что мы будем делать при возникновении ошибок, как снизить вред от ошибок и т.п. и пр.

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

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

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

ВВ>>Но дело даже не в этом. Я предложил подумать и высказать реальные причины, почему что-то реализовано так, а не иначе. Вы же в ответ выдали "ОО-код отражает объективную реальность". Не стоило, право, и начинать

SV.>Я привел конкретный пример и, как мог, объяснил, почему он... нет, не реализован, а ЗАПРОЕКТИРОВАН так, а не иначе. В том-то и дело, что реализовать всегда можно хоть так, хоть иначе, и все будет работать. Теперь я понимаю, почему вы не понимаете наследование интерфейсов. Оно не вам нужно, а тому, кто ваш код будет читать, править, развивать, фиксить баги, строить на его основе плагины и так далее.

Вы не объяснили. Наследование не является средством документирования — как раз напротив, оно может с такой же легкость запутать "читающего", как и помочь ему. Я не вижу как разработчику скайпа поможет то, что вы отнаследовали интерфейсы. Эти интерфейсы слишком абстрактные, чтобы можно было из них что-то вынести. А вот явное декларирование юзкейсов — отсылка сообщений, типы сообщений — вполне потянет на документацию.
Re[5]: Зачем нужно наследование интерфейсов?
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 07.07.12 09:41
Оценка:
ВВ> Если метод полиморфный, то нужные интерфейсы просто навешиваются в констрейнтах.

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

Как будет записываться перегруженный метод S1 если ICollection и IEnumerable независимы?:
IEnumerable S1<T1, T2>(this IEnumerable items, Func<T1, T2> transformer)
{
  foreach (var item in items)
    yield return transformer(item);
}
ICollection S1<T1, T2>(this ICollection items, Func<T1, T2> transformer)
{
   return new LazyCollection(items.Count, items.S1(transformer));
}
Re: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 10:53
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.



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


Вот, специально зарегистрировался даже, чтобы высказаться.
Re[6]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 10:57
Оценка:
Здравствуйте, DarkGray, Вы писали:


ВВ>> Если метод полиморфный, то нужные интерфейсы просто навешиваются в констрейнтах.


DG>методы сейчас нельзя перегрузить по констрейнтам.


DG>Как будет записываться перегруженный метод S1 если ICollection и IEnumerable независимы?:

DG>
DG>IEnumerable S1<T1, T2>(this IEnumerable items, Func<T1, T2> transformer)
DG>{
DG>  foreach (var item in items)
DG>    yield return transformer(item);
DG>}
DG>ICollection S1<T1, T2>(this ICollection items, Func<T1, T2> transformer)
DG>{
DG>   return new LazyCollection(items.Count, items.S1(transformer));
DG>}
DG>



А как будет записываться перегруженный по значениям параметров метод? Точно так же, то есть никак.

Перегрузку по именам надо выкинуть. Она дает некоторое удобство при написании кода, но, ИМХО, никак не при чтении.
Re[2]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.07.12 11:29
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


Ок. Что взамен?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[3]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 11:38
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:


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


AVK>Ок. Что взамен?


Вопрос очень широко поставлен, уточните пожалуйста более детально, что вас интересует — синтаксис, семантика, "абстрактно вообще" или "конкретно в С#", или еще что-то, я попробую ответить.

Вообще взамен предлагаются интерфейсы без наследования и генерик-методы с констраинтами на несколько интерфейсов. Плюс отделяемые элементы для расшаривания функционала, не имеющие состояния — traits, которые можно использовать в качестве строительных кирпичиков при создании классов (вместо наследования реализации). Ну это так, мои мысли.
Re: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 07.07.12 11:38
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.


Я подозреваю, что эта тема навеяна недавно введенными в Ela классами. Я полностью поддерживаю мнение о том, что практика из ФП себя оправдывает: чтобы мне реализовать какую-то функцию над данными, мне достаточно гарантий того, что нужные (используемые мною) операции были однозначно определены, а внутреннее устройство данных меня не касается. Это хорошее средство для повторного использования кода. И я не в восторге от того, что в современном мэйнстриме исторически накопилось столько всего для решения фактически одних и тех же задач: классы, интерфейсы, трейтсы, миксины, джненерики, ещё всякие implicit-ы выдумывают, чтобы с этим как-то ужиться, да могут ещё и макросами всё это помазать. Но в последнее время начинают появляться рациональные зёрна. В этой ветке
Автор: Temoto
Дата: 06.07.12
начали говорить о Go, но не договорили. Интерфейсы у него, фактически, аналог классов типов в Хаскеле или протоколов и типов в Кложуре и т.п.:

...

type Reader interface {
    Read(b []byte) (n int, err error)
}

type Writer interface {
    Write(b []byte) (n int, err error)
}

type ReadWriter interface {
    Reader
    Writer
}

type SectionReader struct {
    ...
}

func (s *SectionReader) Read(p []byte) (n int, err error) {
    ....
}

func some_func(rw ReadWriter) {
    ...
}
...


Здесь ReadWriter лишь указывает на то, что в него включены интерфейсы Reader и Writer (могут быть также и свои операции), наследование здесь косвенное. Фактически, это аналог хаскелевских деклараций вида:

class (Eq a, Show a) => C a where ...

Здесь есть пример реализации функции интерфейса для структуры SectionReader. В Go нет явных секций типа "implementation" или "instance", поэтому у него свои особенности в декларациях, вроде нет необходимости всегда всё реализовывать, т.е. не нужны "NotImplementedException". А в функции "some_func" нет необходимости писать в каких-нибудь вариантах:

— func some_func(rw (Reader, Writer) ) {...}

— func some_func(rw Reader|Writer) {...}

— func some_func(rw a) where a Reader, Writer {...}

Короче говоря, я лишь хочу сказать о том, что в мэйнстриме вроде намечаются сдвиги в нужную сторону, но нирваны пока не видно. У Go свои тараканы, подает надежды новый Rust, но там тоже заметны свои заморочки, да и классы вроде собираются вводить, имхо, нафиг там ненужные. Беда пока...
Re[4]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.07.12 12:10
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Вопрос очень широко поставлен, уточните пожалуйста более детально, что вас интересует — синтаксис, семантика, "абстрактно вообще" или "конкретно в С#", или еще что-то, я попробую ответить.


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

ARK>Вообще взамен предлагаются интерфейсы без наследования и генерик-методы с констраинтами на несколько интерфейсов.


Это не решает проблемы динамической диспетчеризации никак.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[2]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 13:07
Оценка:
Здравствуйте, PSV100, Вы писали:

ВВ>>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.

PSV>Я подозреваю, что эта тема навеяна недавно введенными в Ela классами.

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

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

Вот мне и интересно, чем может быть оправдано введение наследования *на самом деле*. Положим, у нас есть "интерфейсы":

INum
{
  Add,
  Subtract,
  Multiply
}

IFractional [ : INum ]
{
  Divide
}


IFractional в общем логично отнаследовать от INum, тут спору нет. Но... зачем? Что мы теряем, если этого наследования не будет?
Кто-нибудь сможет реализовать IFractional без INum. Ну и что? Я понимаю, что с точки зрения общепринятых, так сказать, норм и того, что написано в учебниках это как бы плохо. Но плохо ли?

Все ведь сводится просто к тому, что описание "типа", который я хочу получить, будет выглядеть как (INum IFractional), а не просто IFractional.

PSV>Короче говоря, я лишь хочу сказать о том, что в мэйнстриме вроде намечаются сдвиги в нужную сторону, но нирваны пока не видно. У Go свои тараканы, подает надежды новый Rust, но там тоже заметны свои заморочки, да и классы вроде собираются вводить, имхо, нафиг там ненужные. Беда пока...
Re: Зачем нужно наследование интерфейсов?
От: Roman Odaisky Украина  
Дата: 07.07.12 13:36
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Что это дает-то в принципе?


Указывает, что все объекты, реализующие один интерфейс, реализуют также и второй.

Как иначе сделать что-нибудь типа GUI-библиотеки, где всё, по чему можно клацнуть, имеет координаты и метод отрисовки, но не всё, что можно отобразить, отзывается на события?
interface Drawable
{
    void draw(Canvas);
}

interface Interactable extends Drawable
{
    void add_event_listener(function<void (Event)>);
}

class Label implements Drawable
{
    void set_title(string);
}

class Button implements Interactable
{
    void set_title(string);
    void set_action(function<void (ClickEvent)>);
}

interface ScreenEvent extends Event
{
    Point get_position();
    Interactable get_target();
}

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

И совершенно другой вопрос, а как часто требуется ООП вообще (крайне нечасто).
До последнего не верил в пирамиду Лебедева.
Re[5]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 14:02
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ARK>>Вопрос очень широко поставлен, уточните пожалуйста более детально, что вас интересует — синтаксис, семантика, "абстрактно вообще" или "конкретно в С#", или еще что-то, я попробую ответить.

AVK>Меня интересует, что будет взамен наследования контрактов, т.е. какой механизм динамической диспетчеризации в языке будет основным, и что взамен наследования реализаций, т.е. как реиспользовать готовые реализации контрактов?

Ну т.е. наследование нужно для подключения реализации? Неужели это без наследования никак не сделать?
Re[6]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 14:20
Оценка:
Здравствуйте, DarkGray, Вы писали:

ВВ>> Если метод полиморфный, то нужные интерфейсы просто навешиваются в констрейнтах.

DG>методы сейчас нельзя перегрузить по констрейнтам.
DG>Как будет записываться перегруженный метод S1 если ICollection и IEnumerable независимы?:
DG>
DG>IEnumerable S1<T1, T2>(this IEnumerable items, Func<T1, T2> transformer)
DG>{
DG>  foreach (var item in items)
DG>    yield return transformer(item);
DG>}
DG>ICollection S1<T1, T2>(this ICollection items, Func<T1, T2> transformer)
DG>{
DG>   return new LazyCollection(items.Count, items.S1(transformer));
DG>}
DG>


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

C<E2> Map<C,E1,E2>(C<E1> seq, Func<E1,E2> fun)
{
 ...
}


Сейчас же на практике аналогичное почему-то всегда возвращает IEnumerable. Строго говоря, работает это примерно так:

public interface IMapable<E1>
{
  IMapable<E2> Map<E2>(Func<E1,E2> fun);
}


И это не самый худший вариант. Почему? Хотя бы потому что здесь мы вводим некую абстракцию. Эта абстракция может быть полезной. Например, мы сможем спроецировать последовальность, не зная конкретного типа этой последовательности. Мы действительно выделили некоторую абстракцию — *сворачиваемость* коллекции.

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

Может быть, стоит просто вот так написать:

LazyCollection S1<T1, T2>(this LazyCollection items, Func<T1, T2> transformer)
{
   return new LazyCollection(items.Count, items.S1(transformer));
}
Re[5]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 14:41
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:


ARK>>Вопрос очень широко поставлен, уточните пожалуйста более детально, что вас интересует — синтаксис, семантика, "абстрактно вообще" или "конкретно в С#", или еще что-то, я попробую ответить.


AVK>Меня интересует, что будет взамен наследования контрактов, т.е. какой механизм динамической диспетчеризации в языке будет основным, и что взамен наследования реализаций, т.е. как реиспользовать готовые реализации контрактов?


Для динамической диспетчеризации достаточно только концепции интерфейса, зачем здесь наследование? Интерфейс и несколько реализаций — классов. Или я чего-то не понял?
Взамен наследования реализации я писал выше — traits. Обзор концепции — http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf

ARK>>Вообще взамен предлагаются интерфейсы без наследования и генерик-методы с констраинтами на несколько интерфейсов.


AVK>Это не решает проблемы динамической диспетчеризации никак.


Почему не решает? Поясните мысль или приведите пример. Википедия, к слову, со мной согласна (http://en.wikipedia.org/wiki/Dynamic_dispatch) — про наследование в статье ни слова.
Re[2]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 14:45
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Что это дает-то в принципе?


RO>Указывает, что все объекты, реализующие один интерфейс, реализуют также и второй.


RO>Как иначе сделать что-нибудь типа GUI-библиотеки, где всё, по чему можно клацнуть, имеет координаты и метод отрисовки, но не всё, что можно отобразить, отзывается на события?


А зачем это вообще нужно?

RO>В ООП очень важно уметь наследовать интерфейсы.


Я думал над этим и пришел к выводу, что это не нужно вообще.
Разумеется, в идеальном мире, в котором весь код можно переписать.
Re[3]: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 07.07.12 15:36
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


ВВ>Причем эти два примера показательны. Протоколы есть нечто чрезвычайно упрощенное, тайпклассы же, напротив, нечто чрезвычайно усложненное. Замечаем при этом, что в Кложуре, где нет наследования протоколов, нет и системы типов — следовательно, и не нужно пытаться выражать какие-то "объединения" интерфейсов, бороться с ограничениями системы типов, все и так работает.


ВВ>Вот мне и интересно, чем может быть оправдано введение наследования *на самом деле*. Положим, у нас есть "интерфейсы":


ВВ>
ВВ>INum
ВВ>{
ВВ>  Add,
ВВ>  Subtract,
ВВ>  Multiply
ВВ>}

ВВ>IFractional [ : INum ]
ВВ>{
ВВ>  Divide
ВВ>}
ВВ>


ВВ>IFractional в общем логично отнаследовать от INum, тут спору нет. Но... зачем? Что мы теряем, если этого наследования не будет?

ВВ>Кто-нибудь сможет реализовать IFractional без INum. Ну и что? Я понимаю, что с точки зрения общепринятых, так сказать, норм и того, что написано в учебниках это как бы плохо. Но плохо ли?

ВВ>Все ведь сводится просто к тому, что описание "типа", который я хочу получить, будет выглядеть как (INum IFractional), а не просто IFractional.


Лично я двумя руками за упрощение. Я не вижу никакого кайфа в иерархии интерфейсов, как таковой. И война с ограничениями системы типов пусть останется для Хаскеля, это его стихия. Проблема в том, что действительно иногда необходимо где-то выразить сущность типа именно как "объединение" (INum IFractional). Имхо, в языках с динамической типизацией, как та же Кложура, возможно, это не так восстребовано. А для Ela есть идеи как указать такие "объединения" ? (сорри, если глупость спрашиваю, я с языком знакомился уже давненько и "по диагонали", и недавно видел здесь инфу про появление "протоколов")
Re[4]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 16:17
Оценка:
Здравствуйте, PSV100

PSV>Лично я двумя руками за упрощение. Я не вижу никакого кайфа в иерархии интерфейсов, как таковой. И война с ограничениями системы типов пусть останется для Хаскеля, это его стихия. Проблема в том, что действительно иногда необходимо где-то выразить сущность типа именно как "объединение" (INum IFractional). Имхо, в языках с динамической типизацией, как та же Кложура, возможно, это не так восстребовано. А для Ela есть идеи как указать такие "объединения" ? (сорри, если глупость спрашиваю, я с языком знакомился уже давненько и "по диагонали", и недавно видел здесь инфу про появление "протоколов")


Так Ela динамически типизированная.
Re[9]: Зачем нужно наследование интерфейсов?
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.07.12 16:21
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Я не понимаю, зачем мне приводить интерфейсы, и как это помогает полиморфизму.

Моему коду нужен ICollection.
Но я могу мой экземпляр ICollection передать в любой алгоритм, работающий с IEnumerable.
По-моему, это удобно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 16:25
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Я не понимаю, зачем мне приводить интерфейсы, и как это помогает полиморфизму.

S>Моему коду нужен ICollection.
S>Но я могу мой экземпляр ICollection передать в любой алгоритм, работающий с IEnumerable.

В таком случае вашему коду нужен не ICollection, а "ICollection+IEnumerable", раз внутри него вызывается нечто, требующее IEnumerable.
Re[10]: Зачем нужно наследование интерфейсов?
От: A13x США  
Дата: 07.07.12 17:17
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, SV., Вы писали:


ВВ>>>Я не знаю, что именно отражает ваш код, и какие именно мессенджеры существуют в жизни — а вы же по ходу уверены, что точно и наверняка знаете какие абстракции будут правильны в 100% случаев. Вот только в 100% эти абстракции оказываются неправильными.

SV.>>Это бывает, да. Но для того и меню Refactor, чтобы в момент осознания несогласованности вашей объектной модели с жизнью его нажимать. И если не лениться и рефакторить код каждый раз, когда это вылезает, то да, НА ПРАКТИКЕ в 100% случаев ваши абстракции будут, как вы выразились, "правильными" (я же имел в виду их неискуственность => удобочитаемость => поддерживаемость).

Можно обобщить — есть набор базовых действий которые могут совершать некоторые сущности, к примеру те же мессенджеры, пример:
1. отправить текст
2. отправить файл
3. установить статус пользователя
N. ... etc.

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

Используя IoC контейнер можно ссылаться на SkypeMessenger как на несколько раздельных интерфейсов внедренных как зависимости в некоторый класс, но я не вижу никаких преимуществ у такого решения.
Re[6]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.07.12 18:17
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

AVK>>Меня интересует, что будет взамен наследования контрактов, т.е. какой механизм динамической диспетчеризации в языке будет основным, и что взамен наследования реализаций, т.е. как реиспользовать готовые реализации контрактов?


ВВ>Ну т.е. наследование нужно для подключения реализации?


В том числе.

ВВ> Неужели это без наследования никак не сделать?


Вообще можно, в существующих мейнстрим языках только ценой большего количества писанины.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[6]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.07.12 18:17
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Для динамической диспетчеризации достаточно только концепции интерфейса, зачем здесь наследование?

ARK> Интерфейс и несколько реализаций — классов. Или я чего-то не понял?

Зачем наследование интерфейсов между собой я ответил в Re[7]: Зачем нужно наследование интерфейсов?
Автор: AndrewVK
Дата: 07.07.12
. А реализация интерфейса это тоже наследование контракта по сути, только с двойной косвенностью и без наследования реализации.

AVK>>Это не решает проблемы динамической диспетчеризации никак.


ARK>Почему не решает?


Потому что все равно нужно наследование или другой какой то механизм. Например алгебраические типы данных ака discriminated unions + РМ. Или мультиметоды. Ты же предлагаешь наследование запретить, а вот что в замен не говоришь.

ARK> Поясните мысль или приведите пример. Википедия, к слову, со мной согласна (http://en.wikipedia.org/wiki/Dynamic_dispatch) — про наследование в статье ни слова.


Второй абзац:

This Object-Oriented feature allows substituting a particular implementation using the same interface, and therefore it enables polymorphism.

В мейнстриме такой механизм называется наследованием (для интерфейсов — реализацией). Статья просто очень обобщенная, описывающая сам принцип, а не конкретные механизмы реализации.
Мне вот интересно — ты действительно считаешь, что наследование не имеет отношения к динамической диспетчеризации, или это прием спора такой?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[7]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 19:11
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:


ARK>>Для динамической диспетчеризации достаточно только концепции интерфейса, зачем здесь наследование?

ARK>> Интерфейс и несколько реализаций — классов. Или я чего-то не понял?

AVK>Зачем наследование интерфейсов между собой я ответил в Re[7]: Зачем нужно наследование интерфейсов?
Автор: AndrewVK
Дата: 07.07.12
. А реализация интерфейса это тоже наследование контракта по сути, только с двойной косвенностью и без наследования реализации.


Хм... Не вижу в том ответе обоснования необходимости наследования.

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

"с наследованием просто писанины меньше, перечислять всю потребную кучу интерфейсов в большой иерархии может быть накладно" — это вопрос синтаксиса, наверное можно сделать что-то типа alias'ов. Перечислять тонну хлама в генериках тоже ведь накладно.

Третий пункт, честно, не очень понял. Что именно наследование задает, повышает и накладывает. Зачем IButton должен быть отнаследован от IControl? Хотелось бы реальный пример.

AVK>>>Это не решает проблемы динамической диспетчеризации никак.


ARK>>Почему не решает?


AVK>Потому что все равно нужно наследование или другой какой то механизм. Например алгебраические типы данных ака discriminated unions + РМ. Или мультиметоды. Ты же предлагаешь наследование запретить, а вот что в замен не говоришь.


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

ARK>> Поясните мысль или приведите пример. Википедия, к слову, со мной согласна (http://en.wikipedia.org/wiki/Dynamic_dispatch) — про наследование в статье ни слова.


AVK>Второй абзац:

AVK>

AVK>This Object-Oriented feature allows substituting a particular implementation using the same interface, and therefore it enables polymorphism.

AVK>В мейнстриме такой механизм называется наследованием (для интерфейсов — реализацией). Статья просто очень обобщенная, описывающая сам принцип, а не конкретные механизмы реализации.

Ага.

AVK>Мне вот интересно — ты действительно считаешь, что наследование не имеет отношения к динамической диспетчеризации, или это прием спора такой?


Наследование безусловно имеет отношение к динамической диспетчеризации. Это одна из форм динамической диспетчеризации. Но не единственная и, более того, по моему мнению, не нужная. В Haskell динамическая диспетчеризация есть, а наследования нет.

P.S. Никакие "приемы спора" я не использую, во всяком случае сознательно.
Re[7]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 19:22
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Зачем наследование интерфейсов между собой я ответил в Re[7]: Зачем нужно наследование интерфейсов?
Автор: AndrewVK
Дата: 07.07.12
. А реализация интерфейса это тоже наследование контракта по сути, только с двойной косвенностью и без наследования реализации.


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

AVK>>>Это не решает проблемы динамической диспетчеризации никак.

ARK>>Почему не решает?
AVK>Потому что все равно нужно наследование или другой какой то механизм. Например алгебраические типы данных ака discriminated unions + РМ. Или мультиметоды. Ты же предлагаешь наследование запретить, а вот что в замен не говоришь.

Не понимаю, честно говоря, какое отношение АлгТД имеют к динамик диспатчу.

AVK>Второй абзац:

AVK>

AVK>This Object-Oriented feature allows substituting a particular implementation using the same interface, and therefore it enables polymorphism.

AVK>В мейнстриме такой механизм называется наследованием (для интерфейсов — реализацией). Статья просто очень обобщенная, описывающая сам принцип, а не конкретные механизмы реализации.
AVK>Мне вот интересно — ты действительно считаешь, что наследование не имеет отношения к динамической диспетчеризации, или это прием спора такой?

А ты правда считаешь, что динамик диспатч возможен только при наследовании? Достаточно утиной типизации вообще-то.
Кстати, приведенная цитата из википедии, мне кажется, не совсем корректна, так как сужает ООП до лишь одного его вида. А вообще еще и протипы есть.
Re[8]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 19:36
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Наследование безусловно имеет отношение к динамической диспетчеризации. Это одна из форм динамической диспетчеризации. Но не единственная и, более того, по моему мнению, не нужная. В Haskell динамическая диспетчеризация есть, а наследования нет.


Ну вообще, если оставить за скобками те же экзистенциалы и полиморфную рекурсию, то в Хаскелле получается как раз наоборот — наследование есть, а динамик диспатча нет.
Re[8]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.07.12 19:37
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Хм... Не вижу в том ответе обоснования необходимости наследования.


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

ARK>Заменяем "выносишь общую часть разных интерфейсов в одного предка" на "выносишь общую часть разных интерфейсов в один отдельный интерфейс" — все остальное то же самое.


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

ARK>это вопрос синтаксиса, наверное можно сделать что-то типа alias'ов.


А зачем? Наследование интерфейсов прекрасно эту задачу решает.

ARK> Перечислять тонну хлама в генериках тоже ведь накладно.


Ну вот пока не приходится тонну хлама перечислять.

ARK>Третий пункт, честно, не очень понял. Что именно наследование задает, повышает и накладывает. Зачем IButton должен быть отнаследован от IControl?


Семантика такая. Я интерфейс IButton проектирую из рассчета, что это контрол. Наследование позволяет этот мой рассчет зафиксировать явно, с проверкой компилятором.

ARK>Полиморфизм нужен. Алгебраические типы — неплохо. А зачем нужно наследование


Затем же, зачем и алгебраические типы.

AVK>>Мне вот интересно — ты действительно считаешь, что наследование не имеет отношения к динамической диспетчеризации, или это прием спора такой?


ARK>Наследование безусловно имеет отношение к динамической диспетчеризации.


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

ARK> Это одна из форм динамической диспетчеризации. Но не единственная


А что, кто то утверждал что единственная?

ARK> и, более того, по моему мнению, не нужная


Отлично, что взамен?

ARK>. В Haskell динамическая диспетчеризация есть, а наследования нет.


В Хаскеле есть ФВП и нет классов и 100% кода построено на этих ФВП. Естественно, наследование там не нужно, да и неприменимо.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[8]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.07.12 19:37
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Да ты не ответил.


Ответил. И оценки говорят, что, как минимум, еще 3 человека считают так же. То что ответ тебе не нравится — я тут не виноват.

ВВ>Не понимаю, честно говоря, какое отношение АлгТД имеют к динамик диспатчу.


Прямое. Единственный их смысл — применение в комплекте с PM (сами по себе, без РМ, это малополезный артефакт). А РМ по АлгТД решает именно что задачу динамической диспетчеризации.

ВВ>А ты правда считаешь, что динамик диспатч возможен только при наследовании?


Попробуй привести цитату, где я подобное утверждаю.

ВВ> Достаточно утиной типизации вообще-то.


AlexRK ничего про нее не писал.

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


Приведенная фраза прекрасно подходит и прототипному ОО. И именно из-за прототипного ОО в ней нет слова inheritance.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[9]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.07.12 19:38
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну вообще, если оставить за скобками те же экзистенциалы и полиморфную рекурсию, то в Хаскелле получается как раз наоборот — наследование есть, а динамик диспатча нет.


Динамическая диспетчеризация есть в любом языке с ФВП.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[9]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 19:40
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ARK>>Наследование безусловно имеет отношение к динамической диспетчеризации. Это одна из форм динамической диспетчеризации. Но не единственная и, более того, по моему мнению, не нужная. В Haskell динамическая диспетчеризация есть, а наследования нет.


ВВ>Ну вообще, если оставить за скобками те же экзистенциалы и полиморфную рекурсию, то в Хаскелле получается как раз наоборот — наследование есть, а динамик диспатча нет.


Ээ... а классы типов это не динамик диспатч? Я не большой спец в Хаскелле, мне казалось, что там нельзя один класс типов отнаследовать от другого.
Re[10]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 19:45
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ВВ>>Ну вообще, если оставить за скобками те же экзистенциалы и полиморфную рекурсию, то в Хаскелле получается как раз наоборот — наследование есть, а динамик диспатча нет.

AVK>Динамическая диспетчеризация есть в любом языке с ФВП.

Ну речь же про наследование. И тайпклассы, с рядом оговорок, это не динамик диспатч.
А с ФВП ты сам прекрасно ответил на вопрос, как же возможен динамик диспатч без наследования. Что, кстати, уже начинает наводить на подозрения
Re[10]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 19:47
Оценка:
Здравствуйте, AlexRK, Вы писали:

ВВ>>Ну вообще, если оставить за скобками те же экзистенциалы и полиморфную рекурсию, то в Хаскелле получается как раз наоборот — наследование есть, а динамик диспатча нет.

ARK>Ээ... а классы типов это не динамик диспатч? Я не большой спец в Хаскелле, мне казалось, что там нельзя один класс типов отнаследовать от другого.

Instance selection — статический. А наследование там есть. Вообще тему, конечно, стоило про Хаскелл создать.
Re[11]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.07.12 19:48
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну речь же про наследование.


Речь про отмену наследования.

ВВ> И тайпклассы, с рядом оговорок, это не динамик диспатч.


Т.е ты сам придумал, что тайпклассы это ДД, и сам же с блеском опровергнул?

ВВ>А с ФВП ты сам прекрасно ответил на вопрос, как же возможен динамик диспатч без наследования.


А такого вопроса никто не задавал. Вопрос был к AlexRK, как он предполагает реализовывать ДД.

ВВ> Что, кстати, уже начинает наводить на подозрения


Ага, на то, что кто то толи не читает топик, толи не понимает смысл прочитанного.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[9]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 07.07.12 19:52
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:


ARK>>Хм... Не вижу в том ответе обоснования необходимости наследования.


AVK>А я не говорил что наследование необходимо. Необходимо средство динамической диспетчеризации.


Безусловно. Это средство — возможность реализации интерфейса несколькими классами. Без наследования интерфейсов и классов.

ARK>>Заменяем "выносишь общую часть разных интерфейсов в одного предка" на "выносишь общую часть разных интерфейсов в один отдельный интерфейс" — все остальное то же самое.


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


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

ARK>>это вопрос синтаксиса, наверное можно сделать что-то типа alias'ов.


AVK>А зачем? Наследование интерфейсов прекрасно эту задачу решает.


Но заодно привносит type cast, который тянет за собой еще гору проблем.

ARK>> Перечислять тонну хлама в генериках тоже ведь накладно.


AVK>Ну вот пока не приходится тонну хлама перечислять.


Бывает, что и приходится. List<Dictionary<string, KeyValuePair<int, int>>> и прочая.

ARK>>Третий пункт, честно, не очень понял. Что именно наследование задает, повышает и накладывает. Зачем IButton должен быть отнаследован от IControl?


AVK>Семантика такая. Я интерфейс IButton проектирую из рассчета, что это контрол. Наследование позволяет этот мой рассчет зафиксировать явно, с проверкой компилятором.


ОК. Хотя необходимость этого тоже под вопросом. Сегодня это winforms-контрол, а завтра контрол из WPF или метро.

ARK>>Полиморфизм нужен. Алгебраические типы — неплохо. А зачем нужно наследование


AVK>Затем же, зачем и алгебраические типы.


AVK>>>Мне вот интересно — ты действительно считаешь, что наследование не имеет отношения к динамической диспетчеризации, или это прием спора такой?


ARK>>Наследование безусловно имеет отношение к динамической диспетчеризации.


AVK>Уже хорошо. Тогда поясни, к чему фраза про то, что в викишной статье про наследование ни слова?


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

ARK>> Это одна из форм динамической диспетчеризации. Но не единственная


AVK>А что, кто то утверждал что единственная?


ARK>> и, более того, по моему мнению, не нужная


AVK>Отлично, что взамен?


Взамен — написал выше вариант.

ARK>>. В Haskell динамическая диспетчеризация есть, а наследования нет.


AVK>В Хаскеле есть ФВП и нет классов и 100% кода построено на этих ФВП. Естественно, наследование там не нужно, да и неприменимо.


Ну вот я и хотел сказать, что динамик диспатч и наследование не являются связанными сущностями.
Re[9]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 19:56
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ВВ>>Да ты не ответил.

AVK>Ответил. И оценки говорят, что, как минимум, еще 3 человека считают так же. То что ответ тебе не нравится — я тут не виноват.

Ответ на вопрос "зачем?" должен, очевидно, приводить какую-то причину. Ты ее не привел, а переформулировал вопрос в других словах. Разделить один интерфейс на несколько — ОК, понятно. А вот зачем их еще при этом наследовать ты, боюсь, не объяснил.
И да, мне казалось, тут не спортивное соревнование, чтобы побежал тот, у кого наберется больше "очков".

ВВ>>Не понимаю, честно говоря, какое отношение АлгТД имеют к динамик диспатчу.

AVK>Прямое. Единственный их смысл — применение в комплекте с PM (сами по себе, без РМ, это малополезный артефакт). А РМ по АлгТД решает именно что задачу динамической диспетчеризации.

Ну при таком подходе можно сказать, что if по integer-ам решает задачу динамической диспетчеризации.

ВВ>>А ты правда считаешь, что динамик диспатч возможен только при наследовании?

AVK>Попробуй привести цитату, где я подобное утверждаю.

Ну вот хотя бы:
AVK>Мне вот интересно — ты действительно считаешь, что наследование не имеет отношения к динамической диспетчеризации, или это прием спора такой?
Кстати, вполне может не иметь

ВВ>> Достаточно утиной типизации вообще-то.

AVK>AlexRK ничего про нее не писал.

Он писал о том, что для динамик диспатча наследование не нужно. Что есть правда. Как, впрочем, и обратное утверждение.
Re[12]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 07.07.12 20:04
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ВВ>>Ну речь же про наследование.

AVK>Речь про отмену наследования.

Ну очевидно надо сначала разобраться, что мы решили отменять.

ВВ>> И тайпклассы, с рядом оговорок, это не динамик диспатч.

AVK>Т.е ты сам придумал, что тайпклассы это ДД, и сам же с блеском опровергнул?

Чего? Где придумал? Где я вообще говорил, что это ДД??
Instance selection обычно статический.

ВВ>>А с ФВП ты сам прекрасно ответил на вопрос, как же возможен динамик диспатч без наследования.

AVK>А такого вопроса никто не задавал. Вопрос был к AlexRK, как он предполагает реализовывать ДД.

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

Вопрос, собственно — где я не прав?

ВВ>> Что, кстати, уже начинает наводить на подозрения

AVK>Ага, на то, что кто то толи не читает топик, толи не понимает смысл прочитанного.

Если кто-то превратно понимает то, что ты пишешь — нас, кстати, уже двое, и мы одинаково тебя неправильно поняли (а ты же любишь голоса считать, или нам тут третьего подождать?) — то причина может быть и в том, что сформулировано неудачно. Проще, наверное, переформулировать, чем выдвигать предположения о том, что с тобой спорят и при этом тебя не читают.
Re[12]: Зачем нужно наследование интерфейсов?
От: SV.  
Дата: 07.07.12 20:46
Оценка:
Здравствуйте, SV., Вы писали:

SV.>http://www.youtube.com/watch?v=jdwyC5HdXYk&amp;t=1m3s

SV.>Обратите внимание на мимику и страдальческую интонацию. Считайте, их я тоже процитировал.

Ссылку открывайте в отдельной вкладке или мотайте руками на 1 минуту 3 секунды. (Движок RSDN весь эффект испортил...).
Re[2]: Зачем нужно наследование интерфейсов?
От: artelk  
Дата: 08.07.12 18:24
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.


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

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

_NN>Старый вариант

_NN>
_NN>interface IEnumerable {}
_NN>interface ICollection : IEnumerable {}
_NN>interface IList : ICollection {}
_NN>


_NN>Новый вариант

_NN>
_NN>interface IEnumerable { }
_NN>interface ICollectionPure { }
_NN>interface IListPure { }

_NN>alias ICollection = IEnumerable | ICollectionPure;
_NN>alias IList = ICollectionPure | IListPure;
_NN>


_NN>P.S.

_NN>Так и к структурной типизации придем

Нужно только, чтобы можно было объявлять поля с типами таких алиасов, возвращать их из методов и т.п.
И вообще:
type ICollection = IEnumerable & ICollectionPure;

ICollection coll = ...;

IA&IB variable1 = ...;
IA variableA = variable1;// ~upcast

type IEnumerable_Or_ICollectionPure  = IEnumerable | ICollectionPure;

IA|IB variable3 = ...;
match(variable3)
{
 | a is IA => ...
 | b is IB => ...
}
//Возможно
variable3.F();//,если  F() есть в обоих интерфейсах (хотя тут подумать надо)

(IA&IB)|IC variable4 = ...;
Re[3]: AlexRK
От: AlexRK  
Дата: 08.07.12 18:35
Оценка:
Здравствуйте, artelk, Вы писали:

A>Нужно только, чтобы можно было объявлять поля с типами таких алиасов, возвращать их из методов и т.п.

A>И вообще:

Такие штуки — пересечение метода по имени в разных интерфейсах — придется скорее всего запретить. Или сделать разрешение каким-нибудь дубовым способом. Вероятность коллизии мала, а усложнение языка для обхода таких ситуаций будет весьма значительное.
Re[6]: Зачем нужно наследование интерфейсов?
От: vdimas Россия  
Дата: 08.07.12 19:17
Оценка:
Здравствуйте, Воронков Василий, Вы писали:


ВВ>Ну т.е. наследование нужно для подключения реализации? Неужели это без наследования никак не сделать?


Ну дык интерфейс — это, считай, кортеж ф-ий, составляющих контракт, а this — идентити реализации. Без наследования ты будет точно такую же механику обыгрывать ручками на кортеже функциональных типов. Где смысл?
Re[6]: AlexRK
От: AlexRK  
Дата: 08.07.12 19:21
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Неочевидно. Приведенный пример спокойно переписывается без наследования интерфейсов.


V>В отсутствии явной зависимости в этих сценариях нужно будет динамическое приведение типов.


Нет, динамического никогда не будет.

V>Предложенный способ через генерики — банально более многословен


В C# — да, а вообще можно синтаксис и получше придумать, как мне кажется.

V>вместо однократной декларации зависимостей ты будешь их объявлять вручную в каждом месте.


Алиасы уже тут обсуждались, не обязательно в каждом месте.
Re[9]: Зачем нужно наследование интерфейсов?
От: vdimas Россия  
Дата: 08.07.12 19:22
Оценка:
Здравствуйте, Воронков Василий, Вы писали:


ВВ>Ну вообще, если оставить за скобками те же экзистенциалы и полиморфную рекурсию, то в Хаскелле получается как раз наоборот — наследование есть, а динамик диспатча нет.


Есть на классах типов. В такую же точно табличную диспетчеризацию и вырождается в бинарнике, как в мейнстримных языках на vtable.
Re[10]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 08.07.12 20:02
Оценка:
Здравствуйте, vdimas, Вы писали:

ВВ>>Ну вообще, если оставить за скобками те же экзистенциалы и полиморфную рекурсию, то в Хаскелле получается как раз наоборот — наследование есть, а динамик диспатча нет.

V>Есть на классах типов. В такую же точно табличную диспетчеризацию и вырождается в бинарнике, как в мейнстримных языках на vtable.

Выбор инстанса — в компайл тайме. В "такую же точно табличную диспетчеризацию" он вырождаться уж точно никак не может. При наивной компиляции он рассахаривается в dictionary passing style.
Re[11]: Зачем нужно наследование интерфейсов?
От: vdimas Россия  
Дата: 08.07.12 20:46
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Выбор инстанса — в компайл тайме.


Нет. Т.е. не обязательно, в этом весь трюк. Там где возможен выбор в compile-time, там классы типов и нафик не упали.


ВВ>В "такую же точно табличную диспетчеризацию" он вырождаться уж точно никак не может.


???

ВВ>При наивной компиляции он рассахаривается в dictionary passing style.


Не нужен там никакой dictionary. Там для каждого динамического случая нужен кортеж из используемых ф-ий тайпкласса. Поищи, разбирали подробно полиморфизм С++ vs полиморфизм Хаскеля.
Там ближайший аналог — это реализация тайпклассов через фиктивные АлгТД, в которых хранятся ф-ии тайпкласса, но выбор ф-ий по коду АлгТД и последующий их вызов ничем принципиально от виртуальных вызовов не отличается.
Re[12]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 08.07.12 21:09
Оценка:
Здравствуйте, vdimas, Вы писали:

ВВ>>Выбор инстанса — в компайл тайме.

V>Нет. Т.е. не обязательно, в этом весь трюк. Там где возможен выбор в compile-time, там классы типов и нафик не упали.

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

ВВ>>В "такую же точно табличную диспетчеризацию" он вырождаться уж точно никак не может.

V>???

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

ВВ>>При наивной компиляции он рассахаривается в dictionary passing style.

V>Не нужен там никакой dictionary. Там для каждого динамического случая нужен кортеж из используемых ф-ий тайпкласса. Поищи, разбирали подробно полиморфизм С++ vs полиморфизм Хаскеля.
V>Там ближайший аналог — это реализация тайпклассов через фиктивные АлгТД, в которых хранятся ф-ии тайпкласса, но выбор ф-ий по коду АлгТД и последующий их вызов ничем принципиально от виртуальных вызовов не отличается.

А ну да, в имитации тайпклассов на С++ используются виртуальные функции, только причем тут Хаскелл?
Тайпклассы Хаскелла это по сути перегрузка функций, которая разрешается во время компиляции.
Re[5]: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 09.07.12 12:41
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, PSV100


PSV>>Лично я двумя руками за упрощение. Я не вижу никакого кайфа в иерархии интерфейсов, как таковой. И война с ограничениями системы типов пусть останется для Хаскеля, это его стихия. Проблема в том, что действительно иногда необходимо где-то выразить сущность типа именно как "объединение" (INum IFractional). Имхо, в языках с динамической типизацией, как та же Кложура, возможно, это не так восстребовано. А для Ela есть идеи как указать такие "объединения" ? (сорри, если глупость спрашиваю, я с языком знакомился уже давненько и "по диагонали", и недавно видел здесь инфу про появление "протоколов")


ВВ>Так Ela динамически типизированная.


Ага, действительно. У меня почему-то в памяти отложилось впечатление, что Ela в процессе развития "скатилась" до строгой статики. Я ещё раз повнимательнее глянул описание классов, действительно, фактически, это протоколы кложуры, но диспетчеризация не только по первому аргументу. Хорошо, что для параметра класса нет требований по реализации других классов, т.е. некая хаскелевская иерархия. Имхо, для понимания структурной логики кода вполне достаточно, что функции объединены в смысловые группы (классы).
Удачи в проекте.
Re[4]: AlexRK
От: PSV100  
Дата: 09.07.12 12:59
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, artelk, Вы писали:


A>>Нужно только, чтобы можно было объявлять поля с типами таких алиасов, возвращать их из методов и т.п.

A>>И вообще:

ARK>Такие штуки — пересечение метода по имени в разных интерфейсах — придется скорее всего запретить. Или сделать разрешение каким-нибудь дубовым способом. Вероятность коллизии мала, а усложнение языка для обхода таких ситуаций будет весьма значительное.


Здесь в теме немного затронули Go, у него как раз есть такие объединения, и для структур тоже (кроме интерфейсов), и "дубовые" правила для конфликтов имён.
Re[6]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 09.07.12 13:15
Оценка:
Здравствуйте, PSV100, Вы писали:

ВВ>>Так Ela динамически типизированная.

PSV>Ага, действительно. У меня почему-то в памяти отложилось впечатление, что Ela в процессе развития "скатилась" до строгой статики.

Боюсь, что прикручивать адекватную систему типов ко всему этому — это уже за пределами возможностей одного человека. Да и все равно язык сильно потеряет в выразительности. Скажем, мой любимый трюк с функциями, тип которых вычисляется в рантайме, будет уже невозможен. А это весьма полезно при создании каких-нибудь DSL-ей — например, для тестов:

test1 = 
  test "Demonstration of espec"
  given [1..5]
    should contain 1
    should contain 3
    shouldn't contain 6
    do reverse
    should be [5,4..1]


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

PSV>Удачи в проекте.

Спасибо.
Re[5]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.07.12 13:19
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ничего не понял. Зачем мне отнаследованный интерфейс приводить к базовому да еще "безопасно"? Зачем мне вообще приводить интерфейс к чему-либо?


Тебе же уже ответили раз 5 — полиморфизм. В данном случае ООП-ный.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 09.07.12 13:35
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.


VD>Я так понимаю ты проникся стуктурной типизацией?


Вопрос не ко мне, но здесь нет никакой структурной типизации. Класс обладает теми интерфейсами, которые явно указаны. И не может реализовывать интерфейсы, только лишь получив набор методов с нужными сигнатурами.
Re[9]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.07.12 13:55
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Я в третий раз уже пишу, что GetItems через генерики не реализуется, но там и интерфейс не нужен.


А зачем ты дженерики то упоминал? И кто такой GetItems?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.07.12 13:59
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Перегрузку по именам надо выкинуть. Она дает некоторое удобство при написании кода, но, ИМХО, никак не при чтении.


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

Кроме того перегрузка она мешает только тем кто не умеет ее готовить (в языках).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Зачем нужно наследование интерфейсов?
От: vpchelko  
Дата: 09.07.12 14:07
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

Не очень хороший пример, вот если потребуется сделать кликабельный Label... начнут городить огород? Лучше давать возможность добавлять обработку сообщений опционально.
Сало Украине, Героям Сала
Re[3]: Зачем нужно наследование интерфейсов?
От: fddima  
Дата: 09.07.12 14:12
Оценка:
Здравствуйте, vpchelko, Вы писали:

V>Не очень хороший пример, вот если потребуется сделать кликабельный Label... начнут городить огород? Лучше давать возможность добавлять обработку сообщений опционально.

Безотносительно хороший/плохой пример — кликабельный Label — это собственно говоря и есть Button, с другой формой лица.
Re[4]: Зачем нужно наследование интерфейсов?
От: vpchelko  
Дата: 09.07.12 14:19
Оценка:
F> Безотносительно хороший/плохой пример — кликабельный Label — это собственно говоря и есть Button, с другой формой лица.

Да с какой стороны посмотреть кликаться мы можем, а там mouseover обрабатывать тоже захотим, даже просто по обычному не кликабельному тексту (менять курсор на выделялку текста).
Сало Украине, Героям Сала
Re[8]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 09.07.12 14:32
Оценка:
Здравствуйте, VladD2

ВВ>>Может быть, стоит просто вот так написать:


ВВ>>
ВВ>>LazyCollection S1<T1, T2>(this LazyCollection items, Func<T1, T2> transformer)
ВВ>>{
ВВ>>   return new LazyCollection(items.Count, items.S1(transformer));
ВВ>>}
ВВ>>


VD>Написать то ты можешь. Но толку от этого не будет. Нужна реализация алгоритма. А структуры данных могут быть (и будут на практике) очень сильно разными. Скажем односвязный список и массив.


И как ты себе представляешь ленивый массив?

VD>Такие штуки прокатят только чем-то вроде классов типов, когда можно сделать по перегрузке (отдельной реализации) для каждого поддерживаемого типа.

VD>Вот только к исходному вопросу это уже отношение не имеет.

Какие такие штуки? Причем тут классы?
Re[12]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 09.07.12 14:59
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, AlexRK, Вы писали:


ARK>>В таком случае вашему коду нужен не ICollection, а "ICollection+IEnumerable", раз внутри него вызывается нечто, требующее IEnumerable.


VD>Очень не многие языки умеют оперировать объединениями типов. Это прикольная концепция, но и наследование вполне решат задачи стоящие на практике.


Ну мы же сейчас вроде как обсуждаем идеологию и философию программирования, а не реальные языки.
Из реальных мне на ум приходит только Ceylon.
Re[8]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 09.07.12 15:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, AlexRK, Вы писали:


ARK>>Перегрузку по именам надо выкинуть. Она дает некоторое удобство при написании кода, но, ИМХО, никак не при чтении.


VD>Практика показывает, что выкидывают языки без перегрузки. Можно потратить пол жизни на доказательство того, что перегрузка не нужна. Но всем на это будет наплевать.


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

VD>Кроме того перегрузка она мешает только тем кто не умеет ее готовить (в языках).


Ну фиг знает. По моему мнению перегрузка облегчает запись, но не чтение.
Re[4]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 09.07.12 15:09
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, AlexRK, Вы писали:


ARK>>Вопрос не ко мне, но здесь нет никакой структурной типизации. Класс обладает теми интерфейсами, которые явно указаны. И не может реализовывать интерфейсы, только лишь получив набор методов с нужными сигнатурами.


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


Да нет, передается именно класс, который реализует некоторый набор интерфейсов. В общем, как генерик-методы в C#.

В принципе, тут можно усмотреть некий намек на структурную типизацию, хотя не в привычном смысле. Единицей "структуры" будет один интерфейс, а главной сущностью — "набор интерфейсов". А при использовании наследования этот самый "набор интерфейсов" жестко зашит в одну сущность.
Re[5]: Зачем нужно наследование интерфейсов?
От: fddima  
Дата: 09.07.12 15:15
Оценка:
Здравствуйте, vpchelko, Вы писали:

V>Да с какой стороны посмотреть кликаться мы можем, а там mouseover обрабатывать тоже захотим, даже просто по обычному не кликабельному тексту (менять курсор на выделялку текста).

Дык всё это можно и с Button. Всё в итоге упирается в конкретный UI фреймворк, и есть ли там невменяемые ограничения.
Re[6]: Зачем нужно наследование интерфейсов?
От: vpchelko  
Дата: 09.07.12 15:30
Оценка:
F> Дык всё это можно и с Button.
Вот опять, нафиг мне все кнопочное (из соображений — грузить в память только необходимое), если мне нужно нарисовать текст и менять курсор / подсветить текст под курсором.
Сало Украине, Героям Сала
Re[7]: Зачем нужно наследование интерфейсов?
От: fddima  
Дата: 09.07.12 16:16
Оценка:
Здравствуйте, vpchelko, Вы писали:

F>> Дык всё это можно и с Button.

V>Вот опять, нафиг мне все кнопочное (из соображений — грузить в память только необходимое), если мне нужно нарисовать текст и менять курсор / подсветить текст под курсором.
А что кнопочного то? Кнопка так и делает. Рисует текст и реагирует на несколько событий.
А с поведенческой точки зрения то кликабельный лэйбл — это как раз самая кнопка.
Re[10]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 09.07.12 18:46
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ВВ>Ты когда пишешь


ВВ>
ВВ>2 + 2
ВВ>12.2 + 12.2
ВВ>


ВВ>то это ведь тоже перегрузка.


Согласен. Хотя вроде бы в окамле операторы разные.

Вообще тут вопрос неоднозначный. Во-первых, в идеальном сферическом языке в вакууме даже оператор сложения не будет перегружен — будет единый тип "число". Во-вторых, если ближе к реальности, то с такой перегрузкой я согласен — она в одном месте и выглядит естественно, т.к. пришла из математики. Даже специальный синтаксис используется, а не обычный вызов метода. А вот другие типы перегрузки как-то не внушают доверия. Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).
Re[12]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 09.07.12 19:25
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


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


ВВ>Ну каждый второй динамический язык именно такой. Один числовой тип — число. И как-то это не очень удобно.


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

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


ВВ>Да нету тут никаких типов перегрузки, это такая же перегрузка, как и любая другая. Особенно в разрезе ML и хаскелл. В Окамле перегрузка такх операторов не работает, потому что там вообще перегрузка не работает. Здесь исключений нет.


Технически разницы нет. Я про то, что математические операторы всем хорошо известны и путаницы не возникнет.

ARK>>Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


ВВ>x == y ?


Ну хорошо, это есть.

ВВ>А, собственно, чем перегрузка функций, которая статическая, вреднее, чем динамик диспатч методов с одинаковым именем?


Сейчас не готов ответить, я подумаю.
Re[13]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 09.07.12 19:40
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


И какое число знаков после запятой должно быть допустимо в идеальном языке?

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


ВВ>>Да нету тут никаких типов перегрузки, это такая же перегрузка, как и любая другая. Особенно в разрезе ML и хаскелл. В Окамле перегрузка такх операторов не работает, потому что там вообще перегрузка не работает. Здесь исключений нет.

ARK>Технически разницы нет. Я про то, что математические операторы всем хорошо известны и путаницы не возникнет.

"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?
Да и кроме математических операторов есть вполне известные всем функции.
Re[12]: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 10.07.12 09:09
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ВВ>>>то это ведь тоже перегрузка.

ARK>>Согласен. Хотя вроде бы в окамле операторы разные.

ВВ>Да, вот только мне лично кажется, что за громкими окамловскими лозунгами "перегрузка есть зло", скрывается банальное убожество недопиленного Хидли-Милнера.

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

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

add x y =  x + y

-- каррируем так:

inc = add 1

-- или так:

map (add 1) [1,2,3]


можно писать так:

add x y =  x + y

-- каррируем так:

inc = add 1 _

-- или так:

map ( add 1 _ ) [1,2,3]

-- и так можно:

map ( _ + 1 ) [1,2,3]

-- или так:

map (it + 1)  [1,2,3]


Имхо, для рядовых смертных так даже понятнее. Возможно будет некая каша, когда подчёркивание "_" есть и слева от равно (в образце при ПМ), так и справа где-то при вызове функции.
Также вероятно, что при разном количестве аргументов Хидли-Милнеру поплохеет. Но зато можно было бы писать так:

add x y =  x + y

inc = add 1 _
inc n = add n _

map inc       [1,2,3]
map (inc 10)  [1,2,3]


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

Я не измучен функциональщиной, лишь изредка покуриваю в эту сторону. Поэтому спрашиваю как человека, познавшего хаскелестроение изнутри. Чем чреват такой "колхоз" в а-ля хаскеле ?
Re[3]: Зачем нужно наследование интерфейсов?
От: Roman Odaisky Украина  
Дата: 10.07.12 09:53
Оценка:
Здравствуйте, vpchelko, Вы писали:

V>Не очень хороший пример, вот если потребуется сделать кликабельный Label... начнут городить огород? Лучше давать возможность добавлять обработку сообщений опционально.


А если потребуется скрестить ужа с ежом? ООП подразумевает незыблемую модель предметной области. Сначала продумать, потом формировать иерархию (вот я не продумывал, я от фонаря привел). Если Label — класс, наследоваться нельзя, и всё. Если есть отдельный интерфейс Captionable { string caption }, то вполне уместно реализовать как его, так и Interactable в некоем классе.

«Сделать кликабельный (интерфейс) Label (класс)» — так задачу ставить нельзя. Добавлять функциональность в завершенные объекты нельзя. Будет нарушен LSP, потому что InteractableLabel is-a Label, но Label is-not-an Interactable. В отличие от интерфейса, контракт класса подразумевает не только реализацию определенных интерфейсов, но также и отсутствие реализации всех остальных (например, на практике это может проявляться в прозрачности для событий, если объект Label загораживает собой кликабельный объект).

Тут возникает другой вопрос, ведь любой класс является сам себе интерфейсом, можно ли наследоваться от этого неявного интерфейса? Наследовать реализацию недопустимо, а вот интерфейс — это вполне укладывается в ООП.
До последнего не верил в пирамиду Лебедева.
Re[4]: Зачем нужно наследование интерфейсов?
От: vpchelko  
Дата: 10.07.12 11:58
Оценка:
Какая стена текста... А не проще ли эту кликабельность ака Interactable отделить от рисуемых объектов.? И вообще обработки сообщений делать отдельно, предлагаемый подход неверен.

А то мы заходим для всех рисуемых обрабатывать еще какие-то сообщения, кроме кликов — с таким подходом будете править базовые классы?...
Сало Украине, Героям Сала
Re[5]: Зачем нужно наследование интерфейсов?
От: vpchelko  
Дата: 10.07.12 12:02
Оценка:
П.с. я о том что это плохой пример иерархии был дан. И такие примеры часто даются во всяких учебниках... в общем плохо.
Сало Украине, Героям Сала
Re[14]: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 10.07.12 13:11
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Variadic functions в той или иной степени сочетаются с каррированием. Посмотри вот, как printf в F# реализован.

ВВ>А если отключить систему типов, то вполне даже неплохо сочетаются — должна быть только возможность как-либо провести зависимость между аргументами. В той же Ela такое вот прекрасно работает в сочетании с каррированными функциями:
ВВ>[...]

ВВ>Это не каррирование. Каррирование это представление функции (a->b)->c в a->b->c. В ML/Haskell все функции уже каррированные. Ты же просто описываешь частичное применение на манер Немерле/Скала.

ВВ>Я бы такое не хотел. Это куча синтаксического мусора и весь поинт-фри пойдет под кат.

ВВ>Вообще без каррирования та же Ela резко потеряет в выразительности. Каррирование просто означает, что все функции принимают ровно один аргумент, но, так как апликация функции имеет очень высокий приоритет и лево-ассоциативна, то код вида: fun x y полностью аналогичен (fun x) y — т.е. *два* вызова функции вместо одной. Это на самом деле очень удобный трюк. Особенно, если нет необходимости типизировать функцию во время компиляции.


ВВ>Я ведь, кажется, тебе приводил пример DSL-я:

ВВ>[...]
ВВ>Где здесь функция, и сколько она аргументов принимает? А если это все с "_" переписать?

ВВ>Чреват вырезанием combinatory style под корень.

ВВ>Ну и бесскобочный вызов функций теряет всякий смысл. В общем получится Скала

Да, я подразумевал именно частичное применение функций, нежели каррирование, как таковое. И как раз навеянное понтами Скалы
Variadic functions как-то вылетели из головы, в Хаскеле их нет, а в Ela опять не доглядел. В общем, с ними жить можно, понятно.

И тогда попутно пару вопросиков, чтобы уже два раза не вставать...

— В Ela есть адаптации вида: "(+) 1 2 3 4" может быть эквивалентно "(+) [1,2,3,4]", если есть "+" для списка, или тупл к списку адаптирован из "(+) 1,2,3,4" или со скобками "(+) (1,2,3,4)". Есть конфликты в синтаксисе в этом случае, или это как-то неправославно ?

— Раз уж тут F# вспомнился, нет ли желания сделать сахар на манер F#-вских единиц измерения:

{h = 14, m = 15, s = 37} => {14h, 15m, 37s} или {14h 15m 37s}

Откровенно говоря, хаскелевские скобки "{}" как-то не очень в нём наглядны. Имхо, лучше обычные скобки, вместо "равно" (чтобы не было лишней путаницы) использовать двоеточие :

(h: 14, m: 15, s: 37)

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

time 14h, 15m, 37s
inc (13h, 14m) 12h

или так:

time (14h 15m 37s)
inc (13h 14m) 12h

или более "стандартнее", что ли:

time (14h, 15m, 37s)
inc (13h, 14m) 12h


Это всё неплохое дополнение к туплам вида: "x => y". Для тех же DSL может пригодиться. Есть имхо по этому поводу?
Re[14]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 10.07.12 13:14
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


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


ВВ>И какое число знаков после запятой должно быть допустимо в идеальном языке?


Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

type Int32 is Number where (value >= 0) and (value <= 2000000000);

function Test(num: Number)
requires
decimal_digits(num) = 3
begin
...

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


ВВ>>>Да нету тут никаких типов перегрузки, это такая же перегрузка, как и любая другая. Особенно в разрезе ML и хаскелл. В Окамле перегрузка такх операторов не работает, потому что там вообще перегрузка не работает. Здесь исключений нет.

ARK>>Технически разницы нет. Я про то, что математические операторы всем хорошо известны и путаницы не возникнет.

ВВ>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?


Если числовой тип один, то все будет в одном экземпляре.
Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.

ВВ>Да и кроме математических операторов есть вполне известные всем функции.


Например? Читать/писать в поток?

ВВ>А, собственно, чем перегрузка функций, которая статическая, вреднее, чем динамик диспатч методов с одинаковым именем?


Подумал. Может быть действительно разницы нет. Если что-то в голову придет, напишу.
Re[15]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 13:44
Оценка:
Здравствуйте, PSV100, Вы писали:

PSV>Да, я подразумевал именно частичное применение функций, нежели каррирование, как таковое. И как раз навеянное понтами Скалы

PSV>Variadic functions как-то вылетели из головы, в Хаскеле их нет, а в Ela опять не доглядел. В общем, с ними жить можно, понятно.

Строго говоря, ни в Ela, ни в Хаскелле, никаких variadic функций нет. Но и там, и там они имитируются за счет того, что функции каррированы. В Хаскелле это тоже возможно:
http://rosettacode.org/wiki/Variadic_function#Haskell
В Ela это делать проще, поскольку нет необходимости вычислять функциональный тип.

Наконец, если хочется "перегрузку" по кол-ву аргументов, то ее спокойно можно записать так:

foo (x,y) = ...
foo (x,y,z) = ...
foo (x,y,z,e) = ...

foo (1,2) //Вызываем


В общем практически как в Си. И разница какая?

PSV>И тогда попутно пару вопросиков, чтобы уже два раза не вставать...

PSV>- В Ela есть адаптации вида: "(+) 1 2 3 4" может быть эквивалентно "(+) [1,2,3,4]", если есть "+" для списка, или тупл к списку адаптирован из "(+) 1,2,3,4" или со скобками "(+) (1,2,3,4)". Есть конфликты в синтаксисе в этом случае, или это как-то неправославно ?

Не, ну все же (+) — это бинарная коммутативная операция, и в классе она описана как a->_. Код вида "(+) [1,2,3,4]" частично применит ее и вернет функцию. А когда попробуешь применить эту функцию к какому-нибудь аргументу, то все вылетит, т.к. нет инстанса.
(+) для списков в теории реализовать можно, но это как-то неправильно.

Вообще я, честно говоря, не понимаю, что все это такое. "(+) 1 2 3 4" работать никак не может, т.к. вот здесь "(+) 1 2" вызов будет сатурирован, и далее мы будем пытаться применить целое число как функцию, что, естественно, не сработает.

Ты меня, наверное, неправильно понял. Variadic функций нет. Все функции принимают один аргумент и что-то возвращают. Функции с несколькими аргументами имитируются тем, что одна функция возвращает другую функцию. Например, (+) можно так описать:

sum = \x -> \y -> x+y
sum 2 3


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

Поэтому все примеры, которые ты привел выше, в Ela не имеют смысла и не работают.

PSV>- Раз уж тут F# вспомнился, нет ли желания сделать сахар на манер F#-вских единиц измерения:

PSV> {h = 14, m = 15, s = 37} => {14h, 15m, 37s} или {14h 15m 37s}
PSV>Откровенно говоря, хаскелевские скобки "{}" как-то не очень в нём наглядны. Имхо, лучше обычные скобки, вместо "равно" (чтобы не было лишней путаницы) использовать двоеточие :
PSV> (h: 14, m: 15, s: 37)

Ну для это надо прошивать какие-то литералы. Хотя вот последний пример мало чем отличается от записи:

{h=14,m=15,s=37}


Запятую вообще нельзя использовать как оператор, и по-другому не будет. Запятая — часть синтаксических конструкций, если ее использовать как оператор, все литералы вида [x,y,z] (x,y) сразу станут неоднозначными.

PSV>Как раз больше напоминает тупл с именованными полями. Да и неплохо бы скобки опускать, когда можно. В итоге:

PSV> time 14h, 15m, 37s
PSV> inc (13h, 14m) 12h

Такой синтаксис противоречит всему остальному.

PSV>или так:

PSV> time (14h 15m 37s)
PSV> inc (13h 14m) 12h
PSV>или более "стандартнее", что ли:
PSV> time (14h, 15m, 37s)
PSV> inc (13h, 14m) 12h
PSV>Это всё неплохое дополнение к туплам вида: "x => y". Для тех же DSL может пригодиться. Есть имхо по этому поводу?

ИМХО в том, что не имея расширяемых литеральных форм, добавлять синтаксис для каждой единицы измерения — это как-то круто. К тому же в большинстве случаев можно записать практически также, но через функции:

time (hr 14, min 15, sec 37)


Или так:

time Hr 14 Min 15 Sec 37
Re[15]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 13:50
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

ARK>type Int32 is Number where (value >= 0) and (value <= 2000000000);

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

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


ВВ>>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?

ARK>Если числовой тип один, то все будет в одном экземпляре.
ARK>Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.

Ну будет та же перегрузка, только в рантайме

ВВ>>Да и кроме математических операторов есть вполне известные всем функции.

ARK>Например? Читать/писать в поток?

Нет, это пример того, как перегрузку использовать не надо.
А вот битовые операции — также вполне известная группа функций.
Re[17]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 16:50
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>>>Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

ARK>>>type Int32 is Number where (value >= 0) and (value <= 2000000000);
ВВ>>Мне кажется, ты просто придумал другой способ описывать числовые типы на основе этих констрейнтов.

Нет, у тебя просто получается, что Int32 — это комплексный тип, который построен на основе "примитивного" типа Number путем навешивания на него "констрейнтов". Так многие числовые типы и сделаны.
К тому же далеко не все так можно выразить. Попробуй так числа Пеано записать.

ВВ>>>>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?

ARK>>>Если числовой тип один, то все будет в одном экземпляре.
ARK>>>Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.
ВВ>>Ну будет та же перегрузка, только в рантайме
ARK>Это не перегрузка, а параметрический полиморфизм. Одна функция по сути, пусть и шаблонная. Если конечно придерживаться общепринятых терминов.

Ты же написал, что типы должны реализовывать интерфейс Numeric. Соответственно, реализаций будет несколько. Можно сделать один набор статических генерик методов, но они будут работать только благодаря тому, что остальные математические функции перегружены.
И, кстати, я не уверен, что так правильно реализовывать тригонометрические функции. Вернее, практически уверен, что неправильно. Например, как ты реализуешь универсальный exp?
Re[18]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 10.07.12 17:20
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ARK>>>>Произвольное. Точнее — такое, какое нужно. Какое указано в предусловии метода, например. Или в констраинте типа.

ARK>>>>type Int32 is Number where (value >= 0) and (value <= 2000000000);
ВВ>>>Мне кажется, ты просто придумал другой способ описывать числовые типы на основе этих констрейнтов.

ВВ>Нет, у тебя просто получается, что Int32 — это комплексный тип, который построен на основе "примитивного" типа Number путем навешивания на него "констрейнтов". Так многие числовые типы и сделаны.


Нет-нет. Это один тип. Алиас — просто механизм для переноса констрейнта во все точки, где он используется. Синтаксический сахар. Полным аналогом будет набор предусловий-постусловий во всех методах, где мы используем этот алиас.

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


В смысле рекурсивное определение числа с помощью единого типа Number? Не представляю — как, наверное нельзя. И не представляю — зачем. Разве что в роли академического упражнения...

ВВ>>>>>"Математические операторы" — это вообще весьма обширный класс функций. Туда ведь и всяческие sin, con входят. Не захочешь же ты писать sinSingle, sinDouble, sinDecimal? Понятнее ведь не будет?

ARK>>>>Если числовой тип один, то все будет в одном экземпляре.
ARK>>>>Если не один, то хорошо бы, чтобы все такие типы реализовывали интерфейс Numeric и методы sin/cos были генерик-методами.
ВВ>>>Ну будет та же перегрузка, только в рантайме
ARK>>Это не перегрузка, а параметрический полиморфизм. Одна функция по сути, пусть и шаблонная. Если конечно придерживаться общепринятых терминов.

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


А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял.

ВВ>И, кстати, я не уверен, что так правильно реализовывать тригонометрические функции. Вернее, практически уверен, что неправильно. Например, как ты реализуешь универсальный exp?


Тут я совсем не копенгаген, беглый обзор википедии не помог. А в чем там сложность?
Re[19]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 17:30
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Здравствуйте, AlexRK, Вы писали:


ВВ>>Нет, у тебя просто получается, что Int32 — это комплексный тип, который построен на основе "примитивного" типа Number путем навешивания на него "констрейнтов". Так многие числовые типы и сделаны.

ARK>Нет-нет. Это один тип. Алиас — просто механизм для переноса констрейнта во все точки, где он используется. Синтаксический сахар. Полным аналогом будет набор предусловий-постусловий во всех методах, где мы используем этот алиас.

Гм, а что тогда такое тип по-твоему?

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

ARK>В смысле рекурсивное определение числа с помощью единого типа Number? Не представляю — как, наверное нельзя. И не представляю — зачем. Разве что в роли академического упражнения...

Ленивые вычисления можно делать, например. Для обычных числовых типов результатом x > 5 будет _|_, если x это _|_. В случае с пеано далеко не обязательно, число может быть вычислено ровно настолько, насколько это нужно, и inf > 5 отработает как надо.

ARK>А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял.


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

ВВ>>И, кстати, я не уверен, что так правильно реализовывать тригонометрические функции. Вернее, практически уверен, что неправильно. Например, как ты реализуешь универсальный exp?


ARK>Тут я совсем не копенгаген, беглый обзор википедии не помог. А в чем там сложность?
Re[16]: Зачем нужно наследование интерфейсов?
От: PSV100  
Дата: 10.07.12 17:31
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Строго говоря, ни в Ela, ни в Хаскелле, никаких variadic функций нет. Но и там, и там они имитируются за счет того, что функции каррированы. В Хаскелле это тоже возможно:

ВВ>http://rosettacode.org/wiki/Variadic_function#Haskell
ВВ>В Ela это делать проще, поскольку нет необходимости вычислять функциональный тип.

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

ВВ>Наконец, если хочется "перегрузку" по кол-ву аргументов, то ее спокойно можно записать так:

ВВ>[...]
ВВ>В общем практически как в Си. И разница какая?

Но это не совсем то, о чём говорилось. Тут проблема в том, что в Хаскеле всё нужно эмулировать и постоянно бороться с системой типов. В результате плодятся функции вида add, add2, map, mapM, mapM_ и т.п. (хотя выделять "...M" возможно полезно, от греха подальше).

ВВ>Не, ну все же (+) — это бинарная коммутативная операция, и в классе она описана как a->_. Код вида "(+) [1,2,3,4]" частично применит ее и вернет функцию. А когда попробуешь применить эту функцию к какому-нибудь аргументу, то все вылетит, т.к. нет инстанса.

ВВ>(+) для списков в теории реализовать можно, но это как-то неправильно.
ВВ>Вообще я, честно говоря, не понимаю, что все это такое. "(+) 1 2 3 4" работать никак не может, т.к. вот здесь "(+) 1 2" вызов будет сатурирован, и далее мы будем пытаться применить целое число как функцию, что, естественно, не сработает.

Это было предположение, что, если реализовать "плюс" для списка, то есть ли сахар, чтобы (для DSL, например) вместо "(+) [1,2,3,4]" написать "(+) 1 2 3 4". В общем-то, да, торможу, при "variadic функциях" и сахарить не нужно.

PSV>>- Раз уж тут F# вспомнился, нет ли желания сделать сахар на манер F#-вских единиц измерения:

PSV>> {h = 14, m = 15, s = 37} => {14h, 15m, 37s} или {14h 15m 37s}
PSV>> [...]
PSV>>Это всё неплохое дополнение к туплам вида: "x => y". Для тех же DSL может пригодиться. Есть имхо по этому поводу?

ВВ>[...]

ВВ>ИМХО в том, что не имея расширяемых литеральных форм, добавлять синтаксис для каждой единицы измерения — это как-то круто.

Здесь имелось в виду то, что метки в records можно писать и как единицы измерения, т.е. {kg=28, gr=190} можно также записать как {28kg, 190gr}. Но при:
time (hr 14, min 15, sec 37)
time Hr 14 Min 15 Sec 37

нет смысла морочить голову.

В общем, в голове были сумбурные мысли под впечатлением примерчиков DSL. Всё прояснилось. Спасибо.
Re[20]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 10.07.12 18:34
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ARK>>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>>Здравствуйте, AlexRK, Вы писали:


ВВ>>>Нет, у тебя просто получается, что Int32 — это комплексный тип, который построен на основе "примитивного" типа Number путем навешивания на него "констрейнтов". Так многие числовые типы и сделаны.

ARK>>Нет-нет. Это один тип. Алиас — просто механизм для переноса констрейнта во все точки, где он используется. Синтаксический сахар. Полным аналогом будет набор предусловий-постусловий во всех методах, где мы используем этот алиас.

ВВ>Гм, а что тогда такое тип по-твоему?


Множество значений с именем (я говорю о номинативной типизации). Если метод требует тип с именем Int32, то Int16 ему передать нельзя.

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

ARK>>В смысле рекурсивное определение числа с помощью единого типа Number? Не представляю — как, наверное нельзя. И не представляю — зачем. Разве что в роли академического упражнения...

ВВ>Ленивые вычисления можно делать, например. Для обычных числовых типов результатом x > 5 будет _|_, если x это _|_. В случае с пеано далеко не обязательно, число может быть вычислено ровно настолько, насколько это нужно, и inf > 5 отработает как надо.


Понятно. Правда, насколько распространены такие задачи... На современных промышленных ЯП такого тоже не сделаешь.

ARK>>А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял.


ВВ>В вычислениях используются различные константы, которые могут иметь разную точность.


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

ВВ>Да и не для всех чисел, поддерживающих остальные арифметические операции, вычисление всяких синусов может иметь смысл.


Наверное тут надо опять работать с предусловиями.
Re[3]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 10.07.12 21:21
Оценка:
Здравствуйте, vpchelko, Вы писали:

V>Нафиг, нужен такой полиморфизм. IPet-ом может быть не только IAnimal, но и IBird, IReptiles, IFish ...


Которые, в свою очередь, являются IAnimal?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[8]: AlexRK
От: fddima  
Дата: 10.07.12 21:24
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Алиасы не спасут. Вот смотри, есть в third party библиотеке некая фабрика с методом "IPet Get()". И что ты будешь делать, если у тебя IPet от IAnimal не отнаследован? Кастить?

AVK>Наследование интерфейсов — неотъемлемая часть контракта, и современная тенденция скорее склонна контракт усложнять и делать более строгим (пре- и постусловия, инвариант и т.п.), нежели наоборот его упрощать.
Это конечно словоблудие всё, но скорее тендеция — упрощать контракт, в том числе и с помощью наследования. Это будет всяко лучше, чем получить неясный кортеж несвязных интерфейсов.
Re[9]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 10.07.12 21:30
Оценка:
Здравствуйте, fddima, Вы писали:

F> Это конечно словоблудие всё, но скорее тендеция — упрощать контракт, в том числе и с помощью наследования. Это будет всяко лучше, чем получить неясный кортеж несвязных интерфейсов.


По усложнением я здесь понимаю расширение ограничительных возможностей.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[21]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 10.07.12 22:32
Оценка:
Здравствуйте, AlexRK, Вы писали:

ВВ>>Гм, а что тогда такое тип по-твоему?

ARK>Множество значений с именем (я говорю о номинативной типизации). Если метод требует тип с именем Int32, то Int16 ему передать нельзя.

Вообще отказ от номинативной типизации вовсе не означает, что у нас становится один тип. Скажем, a'->a'->a' и a'->a' это типы разные, хотя и структурные.
Если уж вести разговор об идеальных языках, то в идеальном языке не должно быть по крайней мере флоатов, ибо они ломают ER. А большинство числовых типов (но не все, ибо это невозможно) могут быть реализованы на базе примитива Integer (arbitrary precision).

ВВ>>Ленивые вычисления можно делать, например. Для обычных числовых типов результатом x > 5 будет _|_, если x это _|_. В случае с пеано далеко не обязательно, число может быть вычислено ровно настолько, насколько это нужно, и inf > 5 отработает как надо.

ARK>Понятно. Правда, насколько распространены такие задачи... На современных промышленных ЯП такого тоже не сделаешь.

В промышленных языках и ленивых контейнеров нет (настоящих по крайней мере). Что ж теперь поделать.

ARK>>>А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял.

ВВ>>В вычислениях используются различные константы, которые могут иметь разную точность.
ARK>Да, я понял. Но это ведь вопрос эффективности, нет? Или принципиально невозможно вычислить синус, имея на руках только базовые операции?

Это не вопрос эффективности, это вопрос точности. Если у тебя какой-нибудь pi захардкожен в double, то мало того, что все числа на свете должны поддерживать арифметику с double, так еще и точность будет соответствующая.
Не говоря уж о том, что тригонометрические и гиперболические ф-ции могут иметь смысл и для комплексных чисел, а реализация вполне может отличаться, т.к. не все остальные операции могут для них иметь смысл.
Мне, честно, кажется, тут очень непросто все. Посмотри на Хаскелл, там есть генерик арифметика и перегруженные литералы, но товарищи даже gcd/lcm в отдельный класс засовывают.

ВВ>>Да и не для всех чисел, поддерживающих остальные арифметические операции, вычисление всяких синусов может иметь смысл.

ARK>Наверное тут надо опять работать с предусловиями.

Ага, и чтобы описать эти предусловия, ты должен ввести свою абстракцию. Например, Transcendental. Вот тебе и "тип".
Re[8]: AlexRK
От: AlexRK  
Дата: 11.07.12 06:03
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:


ARK>>Алиасы уже тут обсуждались, не обязательно в каждом месте.


AVK>Алиасы не спасут. Вот смотри, есть в third party библиотеке некая фабрика с методом "IPet Get()". И что ты будешь делать, если у тебя IPet от IAnimal не отнаследован? Кастить?


Ну если брать язык без наследования интерфейсов, то такая запись означает, что Get() НЕ возвращает IAnimal в принципе и не реализует его методы. Аналогичная ситуация в C# — интерфейс IPet просто не отнаследован от IAnimal. Тут касти — не касти, ничего не сделаешь.

Кстати, еще момент. Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс. ИМХО, код верхнего уровня всегда должен знать конкретные типы (должно быть — "T Get()", где T — генерик-параметр класса, реализующий IPet). А вот "подчиненный" код может иметь дело с неизвестными для него типами. По-моему, в Ada только так и возможно, кстати.

AVK>Наследование интерфейсов — неотъемлемая часть контракта, и современная тенденция скорее склонна контракт усложнять и делать более строгим (пре- и постусловия, инвариант и т.п.), нежели наоборот его упрощать.


Согласен насчет усложнения контрактов. Но насчет наследования пока вашу точку зрения не готов принять.
Re[22]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 11.07.12 06:11
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, AlexRK, Вы писали:


ВВ>>>Гм, а что тогда такое тип по-твоему?

ARK>>Множество значений с именем (я говорю о номинативной типизации). Если метод требует тип с именем Int32, то Int16 ему передать нельзя.

ВВ>Вообще отказ от номинативной типизации вовсе не означает, что у нас становится один тип. Скажем, a'->a'->a' и a'->a' это типы разные, хотя и структурные.


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

ВВ>Если уж вести разговор об идеальных языках, то в идеальном языке не должно быть по крайней мере флоатов, ибо они ломают ER. А большинство числовых типов (но не все, ибо это невозможно) могут быть реализованы на базе примитива Integer (arbitrary precision).


Верно. Абсолютно однозначно плавающей запятой не должно быть, только фиксированная.

ARK>>>>А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял.

ВВ>>>В вычислениях используются различные константы, которые могут иметь разную точность.
ARK>>Да, я понял. Но это ведь вопрос эффективности, нет? Или принципиально невозможно вычислить синус, имея на руках только базовые операции?

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

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

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

ВВ>>>Да и не для всех чисел, поддерживающих остальные арифметические операции, вычисление всяких синусов может иметь смысл.

ARK>>Наверное тут надо опять работать с предусловиями.

ВВ>Ага, и чтобы описать эти предусловия, ты должен ввести свою абстракцию. Например, Transcendental. Вот тебе и "тип".


Спасибо, я посмотрю.
Re[15]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 11.07.12 06:30
Оценка:
Здравствуйте, hi_octane, Вы писали:

ВВ>>И какое число знаков после запятой должно быть допустимо в идеальном языке?

_>Ну конечно же должны быть не убогие знаки после запятой, а абсолютно точные вычисления в обыкновенных дробях! Иначе этим идеальным язком ни один математик пользоваться не станет

А как быть с неалгебраическими числами?
Re[4]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 11.07.12 08:25
Оценка:
Здравствуйте, AndrewVK, Вы писали:

V>>Нафиг, нужен такой полиморфизм. IPet-ом может быть не только IAnimal, но и IBird, IReptiles, IFish ...

AVK>Которые, в свою очередь, являются IAnimal?

Ну так какую иерархию наследования ты здесь предлагаешь?

IPet — IBird — IAnimal?
IPet — IReptiles — IAnimal?
Re[8]: AlexRK
От: Воронков Василий Россия  
Дата: 11.07.12 08:26
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ARK>>Алиасы уже тут обсуждались, не обязательно в каждом месте.

AVK>Алиасы не спасут. Вот смотри, есть в third party библиотеке некая фабрика с методом "IPet Get()". И что ты будешь делать, если у тебя IPet от IAnimal не отнаследован? Кастить?

Third party библиотека должна тогда возвращать (IPet IAnimal), а не просто IPet.
Re[16]: Зачем нужно наследование интерфейсов?
От: hi_octane Беларусь  
Дата: 11.07.12 09:41
Оценка:
ВВ>А как быть с неалгебраическими числами?

Ну два варианта:
1) Задавать точность именно таких чисел, через указание числа разрядов в числителе или знаменателе или в момент использования. Типа там Math.PI(2000). Или Math.Precision = 2000; Math.PI
2) Сворачивать Number * PI в "символьной" форме в Number, который не вычисляет PI, а знает что это функция, и лениво накапливать такие операции, вычисляя с нужной точностью и подставляя в момент Number.GetDouble() или Number.ToString("F20"). Это будет совсем тру.

А чтобы математики рассматривали язык как совсем годный, нужно ещё числа научить размерности за собой таскать и правильно их преобразовывать вместе со значениями.
Re[9]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 10:24
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Ну если брать язык без наследования интерфейсов, то такая запись означает, что Get() НЕ возвращает IAnimal в принципе и не реализует его методы.


Это все понятно. Но делать то что?

ARK> Аналогичная ситуация в C# — интерфейс IPet просто не отнаследован от IAnimal. Тут касти — не касти, ничего не сделаешь.


И это будет трактоваться как ошибка.

ARK>Кстати, еще момент. Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс.


Это называется абстракция. Предлагаешь и ее отменить?

ARK> ИМХО, код верхнего уровня всегда должен знать конкретные типы (должно быть — "T Get()", где T — генерик-параметр класса, реализующий IPet).


Т.е. возможность создания плагинов и аналогичных механизмов хороним в зародыше?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[9]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 10:24
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Third party библиотека должна тогда возвращать (IPet IAnimal), а не просто IPet.


Должна. Вот только с наследованием я могу заставить так делать, а без него — только верить, что меня не забудут.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[10]: AlexRK
От: Воронков Василий Россия  
Дата: 11.07.12 11:42
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, Воронков Василий, Вы писали:

ВВ>>Third party библиотека должна тогда возвращать (IPet IAnimal), а не просто IPet.
AVK>Должна. Вот только с наследованием я могу заставить так делать, а без него — только верить, что меня не забудут.

Вопрос в общем-то остается прежним — зачем *заставлять* так делать? В реальности, это единственный вопрос, на который и нужно ответить в рамках этой темы.
К тому же все эти примеры с GetPet/GetItems немного странные. Либо это вообще неполиморфные функции, и тогда они должны возвращать конкретный класс, а не интерфейс, либо они являются членами, скажем, генерик-класса, и тогда они тем более не будут возвращать интерфейс, а скорее некое T, на которое будут навешаны констрейнты.
Re[6]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 11.07.12 11:45
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, Воронков Василий, Вы писали:

ВВ>>Ну так какую иерархию наследования ты здесь предлагаешь?
AVK>Никакую. Уж сколько лет твердили миру — иерархии идут от конкретных задач, а не из пальца. "ООП это про поведение" (С) Синклер.

Вот только конкретные задачи:

а) меняются
б) бывают поняты неправильно

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

Вот и получается, что сначала отнаследовали IPet от IAnimal, а потом, когда возникла необходимость, стали навешивать сверху всяческие IFish, IBird и пр.
Re[10]: AlexRK
От: AlexRK  
Дата: 11.07.12 12:39
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:


ARK>>Ну если брать язык без наследования интерфейсов, то такая запись означает, что Get() НЕ возвращает IAnimal в принципе и не реализует его методы.


AVK>Это все понятно. Но делать то что?


Василий уже ответил за меня: метод Get из third-party либы должен возвращать IAnimal + IPet, а не просто IPet.

ARK>> Аналогичная ситуация в C# — интерфейс IPet просто не отнаследован от IAnimal. Тут касти — не касти, ничего не сделаешь.


AVK>И это будет трактоваться как ошибка.


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

ARK>>Кстати, еще момент. Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс.


AVK>Это называется абстракция. Предлагаешь и ее отменить?


ИМХО, не все абстракции одинаково полезны.

ARK>> ИМХО, код верхнего уровня всегда должен знать конкретные типы (должно быть — "T Get()", где T — генерик-параметр класса, реализующий IPet).


AVK>Т.е. возможность создания плагинов и аналогичных механизмов хороним в зародыше?


Нет, не хороним (Ada ведь пока существует? ). Просто код, который использует плагины, сам должен быть генерик-кодом.
Re[11]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 12:57
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Василий уже ответил за меня: метод Get из third-party либы должен возвращать IAnimal + IPet, а не просто IPet.


Никому он ничего не должен. Констрейнтов явных нет — значит как повезет.

ARK>>>Кстати, еще момент. Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс.

AVK>>Это называется абстракция. Предлагаешь и ее отменить?
ARK>ИМХО, не все абстракции одинаково полезны.

Какие средства абстрагирования ты предлагаешь взамен?

AVK>>Т.е. возможность создания плагинов и аналогичных механизмов хороним в зародыше?

ARK>Нет, не хороним

Хороним, потому что они все построены на том, что есть well known абстрактный контракт, и плагины его реализуют.

ARK> Просто код, который использует плагины, сам должен быть генерик-кодом.


Да хоть 10 раз, проблемы это не решает. Код хоста принципиально не может знать, какая реализация будет у абстрактного контракта в конкретном плагине.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[11]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 12:57
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Вопрос в общем-то остается прежним — зачем *заставлять* так делать? В реальности, это единственный вопрос, на который и нужно ответить в рамках этой темы.


Затем же, зачем заставлять в статически типизированных языках контролировать соответствие типов. Наследование интерфейсов — неотъемлемая часть контракта. Если я хочу, чтобы любая реализация IPet реализовывала IAnimal (по семантике, проект у меня такой), то я хочу чтобы компилятор это жестко контролировал.

ВВ>К тому же все эти примеры с GetPet/GetItems немного странные. Либо это вообще неполиморфные функции, и тогда они должны возвращать конкретный класс


Абстракции, видишь ли, бывают многоуровневыми. И GetPet таки полиморфен (реализаций IPet может быть много), просто IAnimal это абстракция уровнем выше. Странно другое — что вы почему то уверены, что достаточно ровно два уровня абстракции на все случаи жизни — одноуровневые интерфейсы и один уровень реализации.

ВВ>, а не интерфейс, либо они являются членами, скажем, генерик-класса, и тогда они тем более не будут возвращать интерфейс, а скорее некое T, на которое будут навешаны констрейнты.


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

Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс. ИМХО, код верхнего уровня всегда должен знать конкретные типы ...

Вы уж либо крестик снимите, либо трусы оденьте. Либо отказ от динамического полиморфизма полностью, либо он таки есть, неважно как реализован, наследованием/реализацией интерфейсов, или исчислением каких нибудь кортежей типов интерфейсов.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[7]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 13:00
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


Нет, не предполагает. Рефакторинг никто не отменял. И вопросы, вобщем то, совершенно параллельны конкретно наследованию, и больше относятся к статической типизации в целом.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[11]: AlexRK
От: artelk  
Дата: 11.07.12 13:11
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Василий уже ответил за меня: метод Get из third-party либы должен возвращать IAnimal + IPet, а не просто IPet.

Скорее всего на практике это будет так:
interface IAnimal {...}
interface IPetOnly {...} //:)
alias IPet = IAnimal & IPetOnly;

Метод вернет IPet и все довольны, кроме тех кому этот IPetOnly мозолит глаза, т.к. нигде один не используется — только в связке с IAnimal.
Это все равно, что IList<T> разбить на IReadOnlyList<T> и IChangeOnlyList<T>
Re[12]: AlexRK
От: AlexRK  
Дата: 11.07.12 13:18
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:


ARK>>Василий уже ответил за меня: метод Get из third-party либы должен возвращать IAnimal + IPet, а не просто IPet.


AVK>Никому он ничего не должен. Констрейнтов явных нет — значит как повезет.


Признаться, не понимаю вопроса. Метод не возвращает нужный интерфейс IAnimal — все, это ошибка. То же самое если метод не принимает нужного параметра. В чем вопрос-то?

ARK>>>>Кстати, еще момент. Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс.

AVK>>>Это называется абстракция. Предлагаешь и ее отменить?
ARK>>ИМХО, не все абстракции одинаково полезны.

AVK>Какие средства абстрагирования ты предлагаешь взамен?


Взамен абстрагирования "изнутри"? Я писал в прошлом посте, предлагается вынести знание о создаваемом классе на тот уровень, на котором оно есть.

AVK>>>Т.е. возможность создания плагинов и аналогичных механизмов хороним в зародыше?

ARK>>Нет, не хороним

AVK>Хороним, потому что они все построены на том, что есть well known абстрактный контракт, и плагины его реализуют.

AVK>Да хоть 10 раз, проблемы это не решает. Код хоста принципиально не может знать, какая реализация будет у абстрактного контракта в конкретном плагине.

Код, использующий плагины, на определенном уровне все равно где-то обязательно знает конкретные типы. Такая точка должна быть. Читает из файла конфигурации названия классов, метаданные или еще что-то в этом роде.
Re[12]: AlexRK
От: AlexRK  
Дата: 11.07.12 13:25
Оценка:
Здравствуйте, artelk, Вы писали:

A>Здравствуйте, AlexRK, Вы писали:


ARK>>Василий уже ответил за меня: метод Get из third-party либы должен возвращать IAnimal + IPet, а не просто IPet.

A>Скорее всего на практике это будет так:
A>
A>interface IAnimal {...}
A>interface IPetOnly {...} //:)
A>alias IPet = IAnimal & IPetOnly;
A>

A>Метод вернет IPet и все довольны, кроме тех кому этот IPetOnly мозолит глаза, т.к. нигде один не используется — только в связке с IAnimal.

Ну, можно и обратную ситуацию вообразить для наследования.
IAnimal, IPet и IPetButNotAnimal. Это если предположить, что нам одинаково часто нужны и IPet, и IPetButNotAnimal.

A>Это все равно, что IList<T> разбить на IReadOnlyList<T> и IChangeOnlyList<T>


Боюсь, не все равно. Кстати, такое разделение списка может быть полезным, на мой взгляд.
Re[13]: AlexRK
От: artelk  
Дата: 11.07.12 13:39
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Здравствуйте, artelk, Вы писали:


A>>Здравствуйте, AlexRK, Вы писали:


ARK>>>Василий уже ответил за меня: метод Get из third-party либы должен возвращать IAnimal + IPet, а не просто IPet.

A>>Скорее всего на практике это будет так:
A>>
A>>interface IAnimal {...}
A>>interface IPetOnly {...} //:)
A>>alias IPet = IAnimal & IPetOnly;
A>>

A>>Метод вернет IPet и все довольны, кроме тех кому этот IPetOnly мозолит глаза, т.к. нигде один не используется — только в связке с IAnimal.
Еще нужно следить, чтоб IAnimal и IPetOnly не пересекались по сигнатурам методов.

ARK>Ну, можно и обратную ситуацию вообразить для наследования.

ARK>IAnimal, IPet и IPetButNotAnimal. Это если предположить, что нам одинаково часто нужны и IPet, и IPetButNotAnimal.
А если IPetButNotAnimal нафиг не нужен, но его все равно придется делать, т.к. язык не поддерживает наследования?

A>>Это все равно, что IList<T> разбить на IReadOnlyList<T> и IChangeOnlyList<T>

ARK>Боюсь, не все равно. Кстати, такое разделение списка может быть полезным, на мой взгляд.
Зачем тебе может понадобится IChangeOnlyList?
Re[15]: AlexRK
От: artelk  
Дата: 11.07.12 14:10
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Тут вопрос только в наименовании, так ведь? Ну да, будет кривоватый IPetOnly. Так я же и привожу обратный пример для наследования — там будет ровно та же кривизна, просто в другом случае — когда нам НУЖНЫ два интерфейса, IPet и IPetButNotAnimal.

Так я не против алиасов — очень полезно было бы иметь возможность хранить объекты в посях с типом вида IA&IB. Я против замены ими механизма наследования интерфейсов.
Впринципе, если наследование сделать сахаром к генерации соответствующего интерфейса и алиаса, то было бы хорошо.
Т.е. дано:
interface IB : IA
{
  //новые методы
}

Компилятор генерит:
[Invisible]
interface IB_without_IA
{
  //новые методы
}

alias IB = IA & IB_without_IA;

Только нужно еще решить вопрос переопределения методов (то, что делается сейчас через new).
Re[8]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 11.07.12 14:17
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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

AVK>Нет, не предполагает. Рефакторинг никто не отменял.

Предполагает. Ибо расчитывать каждый раз на рефакторинг *интерфейсов* — это уж больно смелое допущение.

AVK>И вопросы, вобщем то, совершенно параллельны конкретно наследованию, и больше относятся к статической типизации в целом.


Эти вопросы не относятся к статической типизации в целом. Они относятся конкретно к наследованию и к тем зависимостям, которые оно вводит.
Re[12]: AlexRK
От: Воронков Василий Россия  
Дата: 11.07.12 14:27
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ВВ>>Вопрос в общем-то остается прежним — зачем *заставлять* так делать? В реальности, это единственный вопрос, на который и нужно ответить в рамках этой темы.

AVK>Затем же, зачем заставлять в статически типизированных языках контролировать соответствие типов. Наследование интерфейсов — неотъемлемая часть контракта. Если я хочу, чтобы любая реализация IPet реализовывала IAnimal (по семантике, проект у меня такой), то я хочу чтобы компилятор это жестко контролировал.

Связать IPet и IAnimal можно и другими способами, кроме наследования. Ты ведь не просто какие-то интерфейсы выставляешь, но и, скажем, проектируешь некое API, которое с ними работает. Ну и в сигнатурах функций указываешь (IPet IAnimal), вместо последнего.

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

ВВ>>К тому же все эти примеры с GetPet/GetItems немного странные. Либо это вообще неполиморфные функции, и тогда они должны возвращать конкретный класс

AVK>Абстракции, видишь ли, бывают многоуровневыми. И GetPet таки полиморфен (реализаций IPet может быть много), просто IAnimal это абстракция уровнем выше.

Значит, он должен возвращать не IAnimal, а что-то другое. Например:

interface IPetProvider<T> where T : IPet
{
  T GetPet();
}

IPetProvider<FishPet>....


Что, кстати, вполне логично, т.к. поставщик рыбок может и не продавать птичек.

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


Во-первых, чтобы понять, зачем что-либо нужно, самый простой способ — убрать это, и посмотреть, что получается. Таким образом, например, появилась комбинаторика.
Во-вторых, здесь не два уровня абстракции, а бесконечное множество:

FishPet = IPet IFish IAnimal


ВВ>>, а не интерфейс, либо они являются членами, скажем, генерик-класса, и тогда они тем более не будут возвращать интерфейс, а скорее некое T, на которое будут навешаны констрейнты.


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


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

AVK>

AVK>Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс. ИМХО, код верхнего уровня всегда должен знать конкретные типы ...

AVK>Вы уж либо крестик снимите, либо трусы оденьте. Либо отказ от динамического полиморфизма полностью, либо он таки есть, неважно как реализован, наследованием/реализацией интерфейсов, или исчислением каких нибудь кортежей типов интерфейсов.

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

А с утверждением выше я согласен с той оговоркой, что если функция неполиморфна, то не имеет смысла возвращать интерфейс. Если же функция полиморфна, то не имеет смысл ее рассматривать в виде какого-то вырванного из контекста GetItems() без аргументов, который непонятно зачем и для чего. А если расписать целиком всю абстракцию, то есть хорошая такая вероятность, что сразу же найдется и более удачная альтернатива наследованным интерфейсам.
Re[12]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 17:32
Оценка:
Здравствуйте, artelk, Вы писали:

A>Скорее всего на практике это будет так:

A>
A>interface IAnimal {...}
A>interface IPetOnly {...} //:)
A>alias IPet = IAnimal & IPetOnly;
A>

A>Метод вернет IPet

И чем это отличается от наследования?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[14]: AlexRK
От: AlexRK  
Дата: 11.07.12 18:39
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:


AVK>>>Никому он ничего не должен. Констрейнтов явных нет — значит как повезет.


ARK>>Признаться, не понимаю вопроса. Метод не возвращает нужный интерфейс IAnimal — все, это ошибка.


AVK>И? Понимаешь, если я при проектировании сразу заложил наследование IPet от IAnimal, такую ошибку в принципе нельзя сделать, компилятор не даст. Это точно такой же контроль, как и проверка соответсвия сигнатуры реализуемого метода, к примеру. Еще один уровень контроля.


Не понимаю я одно: что конкретно этот контроль дает? Безопасность типов он не повышает. Читабельность тоже не повышает. Зачем он нужен, поясните, пожалуйста. Контроль вида "уж если Get, написанный Васей, вернет IPet, то он точно будет IAnimal, потому что я его (IPet) так реализовал"? ИМХО, сомнительная польза от этого.

AVK>>>Какие средства абстрагирования ты предлагаешь взамен?


ARK>>Взамен абстрагирования "изнутри"? Я писал в прошлом посте, предлагается вынести знание о создаваемом классе на тот уровень, на котором оно есть.


AVK>Ничего не понял.


Это я про ту же "точку знания о конкретных типах".

AVK>>>Да хоть 10 раз, проблемы это не решает. Код хоста принципиально не может знать, какая реализация будет у абстрактного контракта в конкретном плагине.


ARK>>Код, использующий плагины, на определенном уровне все равно где-то обязательно знает конкретные типы.


AVK>Конечно же нет.


Ну хорошо, скажем так: код знает, что будет создан некий класс, реализующий нужный интерфейс. Так что да, как минимум один "магический" метод, из которого выходит неизвестно чего, для поддержки плагинов должен быть (аналог Activator.CreateInstance). А может и не должен... см. ниже.

ARK>> Такая точка должна быть. Читает из файла конфигурации названия классов, метаданные или еще что-то в этом роде.


AVK>И? Как это знание в рантайме поможет компилятору?


Как я понимаю, для JIT проблем быть не должно. Если же речь про "чистую" компиляцию, то да, проблема. Но вообще может оно и не нужно? Это ведь расширение процесса неизвестным кодом. По-моему, от таких вещей надо уходить. В Singularity вроде бы такое расширение запрещено, и это очень правильно.
Re[13]: AlexRK
От: AlexRK  
Дата: 11.07.12 18:43
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, artelk, Вы писали:


A>>Скорее всего на практике это будет так:

A>>
A>>interface IAnimal {...}
A>>interface IPetOnly {...} //:)
A>>alias IPet = IAnimal & IPetOnly;
A>>

A>>Метод вернет IPet

AVK>И чем это отличается от наследования?


IAnimal и IPetOnly не связаны друг с другом. IPet — плоское перечисление интерфейсов. Как следствие, нет приведений типов.
Re[15]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 20:34
Оценка:
Здравствуйте, AlexRK, Вы писали:


ARK>Не понимаю я одно: что конкретно этот контроль дает?


Я уже отвечал на этот вопрос.

ARK>Контроль вида "уж если Get, написанный Васей, вернет IPet, то он точно будет IAnimal, потому что я его (IPet) так реализовал"? ИМХО, сомнительная польза от этого.


Ну а моя ИМХО говорит, что вовсе даже и не сомнительная.

ARK>>>Код, использующий плагины, на определенном уровне все равно где-то обязательно знает конкретные типы.

AVK>>Конечно же нет.

ARK>Ну хорошо, скажем так: код знает, что будет создан некий класс, реализующий нужный интерфейс.


И что ему это знание дает?

ARK> Так что да, как минимум один "магический" метод, из которого выходит неизвестно чего, для поддержки плагинов должен быть (аналог Activator.CreateInstance).


Ну вот позвал ты Activator.CreateInstance, получил object. Дальше ты что с ним будешь делать?

AVK>>И? Как это знание в рантайме поможет компилятору?


ARK>Как я понимаю, для JIT проблем быть не должно.


Каких проблем? При чем тут джит?

ARK> Если же речь про "чистую" компиляцию, то да, проблема.


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

ARK> Но вообще может оно и не нужно?


А, ну понятно. Больше вопросов не имею.

ARK>В Singularity вроде бы такое расширение запрещено, и это очень правильно.


Нет, не запрещено.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[14]: AlexRK
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 11.07.12 20:34
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>IAnimal и IPetOnly не связаны друг с другом.


Абалдеть. Я тож так умею:

interface IPet : IAnimal, IPetOnly {}


ARK>Как следствие, нет приведений типов.


Каких таких приведений?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[16]: AlexRK
От: AlexRK  
Дата: 12.07.12 05:59
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:



ARK>>Не понимаю я одно: что конкретно этот контроль дает?


AVK>Я уже отвечал на этот вопрос.


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

ARK>>Контроль вида "уж если Get, написанный Васей, вернет IPet, то он точно будет IAnimal, потому что я его (IPet) так реализовал"? ИМХО, сомнительная польза от этого.


AVK>Ну а моя ИМХО говорит, что вовсе даже и не сомнительная.


Ну, против ИМХО не попрешь. На одной чаше весов мифический контроль за Васей, на другой — отсутствие исключений при приведении типов. Вам не кажется, что возможность вылета эксепшена — слишком большая цена за такой контроль?

ARK>>>>Код, использующий плагины, на определенном уровне все равно где-то обязательно знает конкретные типы.

AVK>>>Конечно же нет.

ARK>>Ну хорошо, скажем так: код знает, что будет создан некий класс, реализующий нужный интерфейс.


AVK>И что ему это знание дает?


Можно сделать генерик-класс и передать ему созданный объект. Хотя я уже несколько потерял нить разговора.

ARK>> Так что да, как минимум один "магический" метод, из которого выходит неизвестно чего, для поддержки плагинов должен быть (аналог Activator.CreateInstance).


AVK>Ну вот позвал ты Activator.CreateInstance, получил object. Дальше ты что с ним будешь делать?


Не object, а интерфейс. Дальше работаю с ним.

AVK>>>И? Как это знание в рантайме поможет компилятору?


ARK>>Как я понимаю, для JIT проблем быть не должно.


AVK>Каких проблем? При чем тут джит?


JIT может сгенерировать класс в рантайме и подсунуть его нашему генерик-коду. Но все равно — я это уже признал — для этого должен быть "магический" Activator.CreateInstance<T> или аналогичные механизмы. Мы ведь все еще обсуждаем плюсы-минусы (не)возможности выдать из метода "неизвестно что" — просто интерфейс.

ARK>> Если же речь про "чистую" компиляцию, то да, проблема.


AVK>А не понимаю, как тебе наличие имени класса в редактируемом пользователем конфигом поможет решить проблемы отсутствия абстракций. Ты методы у динамически созданного объекта как вызывать собираешься? Тоже через рефлекшен?


Ну почему же, интерфейс будет. Будет метод WorkWithPlugins<T>(T plugin) where T : IPlugin, которому будет передан созданный/загруженный класс.

ARK>> Но вообще может оно и не нужно?


AVK>А, ну понятно. Больше вопросов не имею.


А почему нет? Запускайте отдельный легковесный процесс и общайтесь с ним через каналы (это, разумеется, не про Windows/Linux). По-моему, это куда лучше, чем подцеплять фиг знает что, написанное фиг знает кем, в свое адресное пространство.

ARK>>В Singularity вроде бы такое расширение запрещено, и это очень правильно.


AVK>Нет, не запрещено.


Странно, а вот здесь — http://www.rsdn.ru/article/singularity/singularity.xml
Автор(ы): Galen Hunt, James Larus, Martin Abadi, Mark Aiken, Paul Barham, Manuel Fahndrich, Chris Hawblitzel, Orion Hodson, Steven Levi, Nick Murphy, Bjarne Steensgaard, David Tarditi, Ted Wobber, Brian Zill
Дата: 02.03.2006
Singularity – исследовательский проект Microsoft Research, который начался с вопроса: на что была бы похожа программная платформа, если спроектировать ее на пустом месте, и во главу угла поставить не производительность, а надежность?
— написано такое:

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

и

"Закрытые SIP в Singularity не позволяют использовать кодогенерацию во время исполнения".
Re[15]: AlexRK
От: AlexRK  
Дата: 12.07.12 06:05
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexRK, Вы писали:


ARK>>IAnimal и IPetOnly не связаны друг с другом.


AVK>Абалдеть. Я тож так умею:


AVK>
AVK>interface IPet : IAnimal, IPetOnly {}
AVK>


Это не то же самое. Вы не сможете передать в метод "void PetConsumer(IPet pet)" класс "class Cat: IAnimal, IPetOnly".

ARK>>Как следствие, нет приведений типов.


AVK>Каких таких приведений?


Таких:
  var pet = (IPet)animal;  // OOOPS, InvalidCastException
Re[13]: AlexRK
От: artelk  
Дата: 12.07.12 12:33
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, artelk, Вы писали:


A>>Скорее всего на практике это будет так:

A>>
A>>interface IAnimal {...}
A>>interface IPetOnly {...} //:)
A>>alias IPet = IAnimal & IPetOnly;
A>>

A>>Метод вернет IPet

AVK>И чем это отличается от наследования?


Тем, что алиас. В ситуации, когда нам не нужно различать реализацию IPet от одновременной реализации IAnimal и IPetOnly, лучше подходит алиас.
Другой вопрос — бывает ли так, что нужно? Таки бывает, если вспомнить о контрактах.
Пример: контракт для метода Add интерфейса ICollection<T>:
Contract.Ensures(this.Count >= Contract.OldValue<int>(this.Count), "this.Count >= Contract.OldValue(this.Count)");

Count может не измениться для, например, HashSet<T>.
ICollection<T> наследуется интерфейсом IList<T>, для Add усиливается постусловие:
Contract.Ensures(this.Count == (Contract.OldValue<int>(this.Count) + 1), "Count == Contract.OldValue(Count) + 1");

Итого: если переменная имеет тип IList<T>, то это дает нам больше информации, чем если бы она имела тип ICollection<T> & IListOnly<T>, т.е. в этом случае нужно различать.
Re[11]: AlexRK
От: Klapaucius  
Дата: 13.07.12 07:52
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Просто код, который использует плагины, сам должен быть генерик-кодом.


Он может быть дженерик кодом, но не в том смысле в котором вы предлагаете. В T Get() дженерик у нас такой:
forall T. T <: IPet

В случае плагина так не получится. Но получится так:
exist T. T <: IPet

Т.е. мы сможем вернуть из плагина, например, PetBox с этим типом внутри и элиминировать этот ящик, сделав с этим типом что-то, что позволяет интерфейс IPet. При этом "выпустить" тип "наружу" мы не сможем.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[10]: AlexRK
От: Klapaucius  
Дата: 13.07.12 07:52
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Это называется абстракция. Предлагаешь и ее отменить?


Не в интересах истины, а в интересах правды — абстракция эта дырявая, вплоть до полного несуществования (в динамике, правда, других и не бывает):
(Cat)(IPet)new Cat
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[12]: AlexRK
От: AlexRK  
Дата: 13.07.12 12:34
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Здравствуйте, AlexRK, Вы писали:


ARK>>Просто код, который использует плагины, сам должен быть генерик-кодом.


K>Он может быть дженерик кодом, но не в том смысле в котором вы предлагаете. В T Get() дженерик у нас такой:

K>
K>forall T. T <: IPet 
K>

K>В случае плагина так не получится. Но получится так:
K>
K>exist T. T <: IPet
K>

K>Т.е. мы сможем вернуть из плагина, например, PetBox с этим типом внутри и элиминировать этот ящик, сделав с этим типом что-то, что позволяет интерфейс IPet. При этом "выпустить" тип "наружу" мы не сможем.

Не совсем понял. Если взять C#-подобный язык, то речь идет о классе типа такого:

  class PluginContainer
  {
    private class Internal : IPlugin
    {
      ...
    }

    void Process(Action<IPlugin> agent)
    {
      agent(new Internal());
    }
  }


?

Но ведь нам надо как-то инстанционировать этот сам "ящик" — он ведь будет разный в каждом плагине, раз внутри у него какой-то скрытый тип, у каждого свой. Я понимаю, что в C# подобных штук нет, но может как-нибудь на C#-подобном псевдокоде поясните?
Re[13]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 13.07.12 12:48
Оценка:
Здравствуйте, PSV100, Вы писали:

В принципе, никто и сейчас не мешает объявлять функции вида
foo (a, b, c)

и частично применять их
foo.(1, , 2) -- при включенном расширении TupleSections

Да и перегружать такие функции с помощью тайпклассов можно — выглядит это по хаскельным меркам страшно, по по сравнению с мусором в объявлении функции мейнстримного языка — уже не так плохо.
Но популярность такого подхода в хаскеле равна нулю.
В стандартной библиотеке SML функций, принимающих туплы, еще достаточно много, но в целом по фя карринг победил (что не удивительно).
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[10]: Зачем нужно наследование интерфейсов?
От: vpchelko  
Дата: 13.07.12 12:55
Оценка:
AVK>Так ты предлагаешь вообще от интерфейсов отказаться? Ну, чтобы их не рефакторить?

Нет отказываться не надо, нужен другой подход.
Оставить базовый интерфейс IPet — который описывает поведения и взаимодействие IPet с хозяином.
А дальше конкретных Pet создавать в таком стиле — DogPet extends Dog implements IPet {...}
Сало Украине, Героям Сала
Re[9]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.07.12 23:10
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Практика показывает, что выживают языки, в которые вкладывается много ресурсов. Остальное по большому счету не имеет значения.


Есть такое. Но бабло и пиар не единственные критерии.

ARK>Не думаю, что языковые возможности выживших являются безусловным образцом для подражания.


Безусловно, не являются безусловным образцом. Но их опыт нужно учитывать. И опыт показывает, что людям удобно работать с иерархиями типов. Кстати, это не отрицает возможности работы с объеденениями типов.

Я вообще не понимаю почему Воронков пытается противопоставить иерархии объединениям.

VD>>Кроме того перегрузка она мешает только тем кто не умеет ее готовить (в языках).


ARK>Ну фиг знает. По моему мнению перегрузка облегчает запись, но не чтение.


Я что-то не пойму причем тут чтение. Перегрузка позволяет не выдумывать синтетических имен. Человеку естественно думать о многих вещах как о разновидностях одной и той же сущности. Естественные языки дико перегружены и это нисколько не мешает нам читать написанное на них.

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

Перегрузка, неявные приведения, иерархические системы типов сильно усложняют реализацию компиляторов языков с выводом типов. Но это чисто технические проблемы которые авторы пытаются превратить в идеологические.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.07.12 23:26
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Согласен. Хотя вроде бы в окамле операторы разные.


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

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


Такой язык будет мало кому нужен, так как он будет тормозом. Разные "числа" имеют разные рзмеры и обрабатываются разными инструкциями процессора. Если делать их объектами с поддержкой полиморфизма, то арифметика станет настолько медленной, что ты сам бросишь этот язык. "Число", кстати, еще и точность имеет. Вот в скриптах на эти детали забивают. Но результат — тормоза.

ARK> Во-вторых, если ближе к реальности, то с такой перегрузкой я согласен — она в одном месте и выглядит естественно, т.к. пришла из математики.


Очередной поиск отмазки. Какая тут на фиг математика? В ней что есть понятие размерности типов или отсутствие плавающей точки? Это все детали архитектуры процессоров влияют.

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


Это ровным счетом ничего не меняет. Просто традиции.

ARK> А вот другие типы перегрузки как-то не внушают доверия.


Ну, попробуй обосновать свое недоверие. Уверяю тебя скатишься до тех же табу, что и авторы ОКамла. А реальность она прозоична — перегрузка не вписывется в примитивные алгоритмы вывода типов вроде Хиндли-Милнера. Вот и выбрасывают ее чтобы упростить себе жизнь. В Немерле есть и перегрузка, и неявные приведения типов, но проблем при чтении кода (и в других случаях) не возникает. А раз есть хотя бы один пример опровергающий правило, значит это не правило, а подтасовка.

ARK>Кстати, я тут подумал — не припомню в своих проектах интенсивного использования перегрузки (хотя у других людей опыт другой, конечно).


Припоминаю в своих проекта массовое использование перегрузок. Что это меняет?

Как бы разговор о вреде перегрузки — это разговор в пользу бедных. Все самые массовые языки ее поддерживают. Значит в ней точно вреда нет. На сегодня основные библиотеки пишутся как раз для языков с перегрузкой. Если есть желание жить в современном мире и пользоваться современными библиотеками, то поддерживать перегрузку (хотя бы для интеропа) жизненно необходимо. Иначе язык будет сфериоконем вакуумным.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.07.12 00:01
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>но в целом по фя карринг победил (что не удивительно).


В целом по ФЯ — они слили. В мэйнстрим им не попасть. Туда пойдут гибриды. Ставлю ящик пива, что они будут карринга.

Людям не нужны ФЯ. Людям нужно решать свои проблемы. Причем здесь и сейчас.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 15.07.12 06:50
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, AlexRK, Вы писали:


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


VD>Такой язык будет мало кому нужен, так как он будет тормозом. Разные "числа" имеют разные рзмеры и обрабатываются разными инструкциями процессора. Если делать их объектами с поддержкой полиморфизма, то арифметика станет настолько медленной, что ты сам бросишь этот язык. "Число", кстати, еще и точность имеет. Вот в скриптах на эти детали забивают. Но результат — тормоза.


Не-не, я имею в виду не тот вариант, который применяется в скриптах. Имеется в виду нечто типа языка Ada: http://en.wikibooks.org/wiki/Ada_Programming/Type_System. Т.е. реальные типы всегда имеют конечные размеры и точность, а вот алгоритмы абстрактны — могут работать с любыми Integer или Real.

ARK>> А вот другие типы перегрузки как-то не внушают доверия.


VD>Ну, попробуй обосновать свое недоверие. Уверяю тебя скатишься до тех же табу, что и авторы ОКамла. А реальность она прозоична — перегрузка не вписывется в примитивные алгоритмы вывода типов вроде Хиндли-Милнера. Вот и выбрасывают ее чтобы упростить себе жизнь. В Немерле есть и перегрузка, и неявные приведения типов, но проблем при чтении кода (и в других случаях) не возникает. А раз есть хотя бы один пример опровергающий правило, значит это не правило, а подтасовка.

VD>Припоминаю в своих проекта массовое использование перегрузок. Что это меняет?
VD>Как бы разговор о вреде перегрузки — это разговор в пользу бедных. Все самые массовые языки ее поддерживают. Значит в ней точно вреда нет. На сегодня основные библиотеки пишутся как раз для языков с перегрузкой. Если есть желание жить в современном мире и пользоваться современными библиотеками, то поддерживать перегрузку (хотя бы для интеропа) жизненно необходимо. Иначе язык будет сфериоконем вакуумным.

Сейчас не готов серьезно обсуждать перегрузку. Мне эта концепция давно не нравится, хотя возможно я не прав. В принципе, если нет иерархий типов и неявных приведений, плюс если можно перегружать по возвращаемому значению, то, возможно, оно не так уж плохо (но это опять же к современным мейнстрим-языкам не относится ).
Re[13]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.07.12 09:32
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Не-не, я имею в виду не тот вариант, который применяется в скриптах. Имеется в виду нечто типа языка Ada: http://en.wikibooks.org/wiki/Ada_Programming/Type_System. Т.е. реальные типы всегда имеют конечные размеры и точность, а вот алгоритмы абстрактны — могут работать с любыми Integer или Real.


Сдается не что Агда и есть тормоз. Есть физические проблемы. Их невозможно преодолеть. Перегрузка это единственное решение не дающее замедление. Тут еще упоминались шаблоны, но специализация шаблонов — это форма перегрузки.

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

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


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

Людям удобно думать в терминах иерархий типов, перегрузок и неявных приведений (которые по сути являются разновидностью сабтайпинга).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 17.07.12 08:15
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Нет. Т.е. не обязательно, в этом весь трюк. Там где возможен выбор в compile-time, там классы типов и нафик не упали.


Вот так новости. Классы типов для выбора в компайл тайм и предназначались. Для первого применения тайпклассов — полиморфной арифметики — это вообще критично. Это уже позже появились возможности реифицировать словарь и организовать выбор в рантайме.

V>Не нужен там никакой dictionary. Там для каждого динамического случая нужен кортеж из используемых ф-ий тайпкласса.


Передача кортежа функций и называется dictionary passing style, а кортеж функций называется dictionary.

V>Там ближайший аналог — это реализация тайпклассов через фиктивные АлгТД, в которых хранятся ф-ии тайпкласса


Не через фиктивные, а вполне реальные (до какого-то прохода оптимизатора, по крайней мере).

V>но выбор ф-ий по коду АлгТД и последующий их вызов ничем принципиально от виртуальных вызовов не отличается.


Это касается типов-сумм (вариантов). Словарь тайпкласса же это не сумма, а произведение (кортеж). Нет для кортежей никакой диспетчеризации — выбирать-то не из чего. Поэтому и вызовы не нужны, не то что диспетчеризация. На практике, разрешение тайпклассов вот в таком вот коде:

import Control.Monad
import Control.Monad.Instances

foo :: Int -> Int
foo = join (+)

bar :: Double -> Double
bar = join (+)

main = do 
    n <- getLine
    print . foo . read $ n 
    print . bar . read $ n


приведет к тому, что foo и bar превратятся просто в
x +# x
x +## x

соотвественно. Т.е. мономорфные сложения интов и даблов. Статичнее уже просто некуда. От словарей не осталось ничего. Словари нужны только для полиморфного кода, лежащего в библиотеке, а выполняется-то мономорфный. Но даже без всякого инлайна, при сохранении словаря — нет никакой диспетчеризации. Потому, что кортеж — не вариант. Аналог структуры, а не аналог (отдаленный) иерархии классов.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[15]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 17.07.12 10:30
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В целом по ФЯ — они слили. В мэйнстрим им не попасть. Туда пойдут гибриды. Ставлю ящик пива, что они будут карринга.


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

VD>Людям не нужны ФЯ. Людям нужно решать свои проблемы. Причем здесь и сейчас.


Мне нужны. ФЯ решают часть моих проблем. Да, уже сейчас, даже принимая во внимание всю их сырость. И, по мере совершенствования, будут решать все болше, а создавать — все меньше.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[16]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.07.12 10:35
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Свою позицию по ФЯ и мейнстриму я уже не раз тут декларировал. Очевидно, что в мейнстрим сначала попадут гибриды. Так обычно и бывает: гибрид — это переходное решение. После гибридов в мейнстрим пойдут чистые ФЯ.


Готов поспорить на что угодно, что в мейнстриме чистых ФЯ не будет никогда.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[17]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 17.07.12 11:37
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Готов поспорить на что угодно, что в мейнстриме чистых ФЯ не будет никогда.


Я бы поспорил, но спор нечестный: я его в принципе не могу проиграть (даже если ФЯ действительно не попадут в мейнстрим никогда), в отличие, например, от спора, что чистые ФЯ не попадут в мейнстрим в ближайшие 10 лет.

А что по-вашему, будет следующим мейнстримом? Или нас ожидает конец истории?
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[18]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 17.07.12 13:47
Оценка:
Здравствуйте, Klapaucius, Вы писали:

AVK>>Готов поспорить на что угодно, что в мейнстриме чистых ФЯ не будет никогда.

K>Я бы поспорил, но спор нечестный: я его в принципе не могу проиграть (даже если ФЯ действительно не попадут в мейнстрим никогда), в отличие, например, от спора, что чистые ФЯ не попадут в мейнстрим в ближайшие 10 лет.
K>А что по-вашему, будет следующим мейнстримом? Или нас ожидает конец истории?

Мне кажется, тут следует вначале задать другой вопрос — а что *нужно* мейнстриму? Я вот не уверен, что мейнстриму нужны языки общего назначения в принципе. Мейнстриму, скорее, нужны крайне ограниченные "доменные" языки, заточенные под решение узкого круга специальных задач. Т.о. программирование превращается скорее в этакую "конфигурацию" софта. Тенденция такая, однако, намечается.
Re[16]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.07.12 14:23
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Свою позицию по ФЯ и мейнстриму я уже не раз тут декларировал. Очевидно, что в мейнстрим сначала попадут гибриды. Так обычно и бывает: гибрид — это переходное решение. После гибридов в мейнстрим пойдут чистые ФЯ.


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

Но часто фишки ФП могут упростить задачу. Так что смесь ФП и МП будет только развиваться.

Когда мэйнстрим полностью впитает ФП, то говорить о чистых ФЯ просто не придется.

K>Когда они устареют — тотальное программирование.


Второй раз слышу это словосочетание. Гугль ничего не объясняет. Что это значит?

K>А что после него будет — еще непонятно. Пока паровые машины сырые и ненадежные, пока опыт их эксплуатации не накоплен — в мейнстриме параходофрегаты. Когда паровые машины доведены до приемлемого качества — в мейнстриме пароходы.


Я ставлю на ДСЛ-и и МП. А ФП, ООП будут позволять упростить генерацию кода для них.
Паровые машины (Лисп) не предлагать. Не тот уровень юзабельности.

VD>>Людям не нужны ФЯ. Людям нужно решать свои проблемы. Причем здесь и сейчас.


K>Мне нужны. ФЯ решают часть моих проблем. Да, уже сейчас, даже принимая во внимание всю их сырость. И, по мере совершенствования, будут решать все болше, а создавать — все меньше.


Ты явно не из числа тех кого можно к мэйнстриму отнести. Тебе и еще кому-то нужны. Но людям в целом — нет. Уровень решения задач все равно крайне низкий. Мозголомство страшное. Не взлетит.

А вот ФП-шные фишки в мэйнстрим впитаются. Лямбды уже тут. Паттерн-матчингу пока мэйнстрим сопротивляется, но в течеии лет 10 сдастся.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.07.12 14:25
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>А что по-вашему, будет следующим мейнстримом?


Гибриды. Т.е. языки с полноценной поддержкой и ООП и ФЯ. Типа Scala или Kotlin.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[19]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.07.12 14:25
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Т.о. программирование превращается скорее в этакую "конфигурацию" софта. Тенденция такая, однако, намечается.


Не знаю откуда ты такую тенденцию взял, но почти все новые мейнстрим-языки сложнее своих предков. Безусловно, область "конфигурации" тоже растет и развивается, но то, что конфигурировать, его ведь тоже кто то написать должен.
Вообще, развитие разработки софта идет пока в строгом соответствии с законом развития сложных систем — новый инструментарий постоянно закрывает области, где раньше требовалось рукопашное программирование, но оставшиеся незакрытые растут в объеме еще быстрее, да новые появляются.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[17]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 17.07.12 14:26
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Klapaucius, Вы писали:


K>>Когда они устареют — тотальное программирование.


VD>Второй раз слышу это словосочетание. Гугль ничего не объясняет. Что это значит?


Видимо, речь о программах, которые гарантировано и формально доказано не содержат ошибок времени исполнения. А функции, которые имеют ограниченную область определения, не могут быть вызваны вне этой области.
Re[20]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 17.07.12 15:08
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, Воронков Василий, Вы писали:

ВВ>>Т.о. программирование превращается скорее в этакую "конфигурацию" софта. Тенденция такая, однако, намечается.
AVK>Не знаю откуда ты такую тенденцию взял, но почти все новые мейнстрим-языки сложнее своих предков.

Какие именно языки? Каких проще?
Java, когда появилась, была весьма примитивным языком, да и сейчас недалеко ушла.
C#, даже современный, по-прежнему как язык проще, чем C++.

AVK>Безусловно, область "конфигурации" тоже растет и развивается, но то, что конфигурировать, его ведь тоже кто то написать должен.


Бесспорно. Точно так же, как надо будет писать драйвера, выпускать новые версии операционных систем и т.д. Вот только это уже не мейнстрим задачи.

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


А что ты называешь мейнстримом? Собственно, я бы сказал, что мейнстрим — это как раз *закрытые* области. Чисто количественно разработки, которая ведется в этих закрытых областях, гораздо больше, чем в "незакрытых" и еще только осваиваемых.
Если же для тебя мейнстрим — просто синоним промышленного программирования, то тогда твой тезис об ФЯ вообще непонятен. ФЯ уже используются в индустрии.
Re[14]: AlexRK
От: AlexRK  
Дата: 17.07.12 18:45
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Здравствуйте, AlexRK, Вы писали:


K>Т.е. если убрать отношения сабтайпинга между классом и реализуемым им интерфейсом и оставить только интерфейсы как констрейнты — нужны экзистенциальные типы и полиморфизм ранга 2.

K>Если убрать наследование вообще и оставить только имплементацию интерфейсов, то диспетчеризация будет статической ("интерфейсные" вызовы можно вовсе заинлайнить) для всех универсальных (forall) типов (как сейчас для struct и интерфейсов-констрейнтов) и динамической для всех экзистенциальных (exist). Т.е. какой-то оверхед от полиморфизма останется только в тех случаях, когда без него не обойтись. Устранять же всеобщую виртуальность вызовов в тех случаях, где она не нужна (почти везде) хоть и кое-как можно, но это весьма нетривиально.

Спасибо за ответ. Помедитировал над ним. Если я правильно понял — по сути это тот же возврат интерфейса: "IPet Get()". С той разницей, что возвращается таки не интерфейс, а неизвестный класс. Т.е. экзистенциальные типы — это такая языковая лазейка, чтобы работать с типами, а интерфейсы использовать только в качестве констрейнтов. Этакий "генерик-параметр на выход". Интересная концепция, жаль только, что применения в других местах языка ей пока не вижу — только для возврата из метода неизвестных типов.
Re[21]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.07.12 19:12
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Java, когда появилась, была весьма примитивным языком,


Значительно сложнее С.

ВВ>да и сейчас недалеко ушла.


Тем не менее усложняется с каждым релизом.

ВВ>C#, даже современный, по-прежнему как язык проще, чем C++.


Он сложнее, просто интуитивнее.

ВВ>Бесспорно. Точно так же, как надо будет писать драйвера, выпускать новые версии операционных систем и т.д. Вот только это уже не мейнстрим задачи.


Докажи.

ВВ>А что ты называешь мейнстримом?


То, что потребляет основное количество денег на разработку.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[22]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 17.07.12 20:04
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ВВ>>Java, когда появилась, была весьма примитивным языком,

AVK>Значительно сложнее С.

Во-первых, не все так просто как кажется. Джава на момент появления была как C# 1.0 — минус ряд фич.
Си же не такой уж и простой на самом деле.

И Джава все-таки не Си противопоставлялась, а скорее С++.

ВВ>>да и сейчас недалеко ушла.

AVK>Тем не менее усложняется с каждым релизом.

Ну да, раз в 10 лет. "Предки" Джавы тоже с каждым релизом усложняются — примерно с той же скоростью к тому же.

ВВ>>C#, даже современный, по-прежнему как язык проще, чем C++.

AVK>Он сложнее, просто интуитивнее.

Я не думаю. Один факт того, что система типов в С++ является тьюринг полной, как бы вызывает сомнения в необходимости дальнейшего сравнения.
Нет, ты правда считаешь, что С# 4.0 как язык сложнее, чем С++11?

ВВ>>Бесспорно. Точно так же, как надо будет писать драйвера, выпускать новые версии операционных систем и т.д. Вот только это уже не мейнстрим задачи.

AVK>Докажи.

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

Мне на самом деле все равно, что в твоих глазах является мейнстримом, а что не является. Но ты сказал, что ФЯ в мейнстриме не будет. Изволь тогда объяснить, где именно его не будет, чтобы не было спора о терминах.

ВВ>>А что ты называешь мейнстримом?

AVK>То, что потребляет основное количество денег на разработку.

Корпоративный сегмент.
Re[23]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.07.12 20:18
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну да, раз в 10 лет. "Предки" Джавы тоже с каждым релизом усложняются — примерно с той же скоростью к тому же.


Это неважно. Главное — тенденция.

ВВ>Я не думаю.


Сравни размер спецификаций.

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


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

ВВ>>>Бесспорно. Точно так же, как надо будет писать драйвера, выпускать новые версии операционных систем и т.д. Вот только это уже не мейнстрим задачи.

AVK>>Докажи.

ВВ>Ты вообще интересный человек. Сделал некое заявление


Заявление сделал ты, а не я. Оно процитировано выше.

ВВ>>>А что ты называешь мейнстримом?

AVK>>То, что потребляет основное количество денег на разработку.

ВВ>Корпоративный сегмент.


В основном. Но и компании типа МС тоже серьезная доля.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[24]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 17.07.12 20:40
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, Воронков Василий, Вы писали:

ВВ>>Ну да, раз в 10 лет. "Предки" Джавы тоже с каждым релизом усложняются — примерно с той же скоростью к тому же.
AVK>Это неважно. Главное — тенденция.

Я указанной тобой тенденции не вижу.

ВВ>>Я не думаю.

AVK>Сравни размер спецификаций.

Спека шарпа — ок. 500 стр. Размер спеки С++11 — что-то около 1500 стр., насколько я помню. Немного больше

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


AVK>Брейнфак тоже тьюринг полный. Что не делает его сложным. Плюсовые шаблоны строятся по сравнительно простым правилам, а то что они позволяют мозговыковыривательный код писать — это к сложности самого языка имеет опосредованное отношение.


Т.е. тьюринг полнота системы типов к сложности никакого отношения не имеет? А что же тогда имеет? Что такого сложного в C#?

ВВ>>>>Бесспорно. Точно так же, как надо будет писать драйвера, выпускать новые версии операционных систем и т.д. Вот только это уже не мейнстрим задачи.

AVK>>>Докажи.
ВВ>>Ты вообще интересный человек. Сделал некое заявление
AVK>Заявление сделал ты, а не я. Оно процитировано выше.

Повторюсь, мне неинтересно спорить о том, что такое мейнстрим. Если этот термин вызывает различные трактовки, не проще ли переформулировать свою изначальную мысль
Автор: AndrewVK
Дата: 17.07.12
?
Или это не наш путь, и мы теперь будем двадцать страниц спорить о мейнстриме?

ВВ>>>>А что ты называешь мейнстримом?

AVK>>>То, что потребляет основное количество денег на разработку.
ВВ>>Корпоративный сегмент.
AVK>В основном. Но и компании типа МС тоже серьезная доля.

Ну вот там и нужны в первую очередь "конфигураторы".
Re[18]: Зачем нужно наследование интерфейсов?
От: VladD2 Российская Империя www.nemerle.org
Дата: 17.07.12 21:07
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


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

И самое смешное — большая часть рантайм-ошибок никогда не встретятся на практике. А стало быть усилия будут потрачены на практике.

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

В любом случае это никак не даст повышения уровня кода. Доказанность и безошибочность только усложняют кода, а не упрощают. В то же время ДСЛ-и позволяют как сделать код проще и короче, так и повысить его защищенность от ошибок, так как ДСЛ просто может не содержать конструкций приводящих к этим ошибкам.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[25]: Зачем нужно наследование интерфейсов?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.07.12 21:51
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Спека шарпа — ок. 500 стр. Размер спеки С++11 — что-то около 1500 стр., насколько я помню. Немного больше


С++ 11 моложе шарпа значительно, так что это только подтверждает то, что я говорю.

AVK>>Заявление сделал ты, а не я. Оно процитировано выше.

ВВ>Повторюсь, мне неинтересно спорить о том, что такое мейнстрим.

Так не спорь.

ВВ> Если этот термин вызывает различные трактовки, не проще ли переформулировать свою изначальную мысль
Автор: AndrewVK
Дата: 17.07.12
?


Мне проще просто бросить с тобой общаться в очередной раз.

AVK>>В основном. Но и компании типа МС тоже серьезная доля.

ВВ>Ну вот там и нужны в первую очередь "конфигураторы".

Смотря что понимать под конфигураторами. Если мальчиков, которые подправляют готовые решения это одно, а если те, кто пишет сами прикладные решения, пусть и на готовой платформе — это совсем другое.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[26]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 18.07.12 05:30
Оценка:
Здравствуйте, AndrewVK, Вы писали:

ВВ>>Спека шарпа — ок. 500 стр. Размер спеки С++11 — что-то около 1500 стр., насколько я помню. Немного больше

AVK>С++ 11 моложе шарпа значительно, так что это только подтверждает то, что я говорю.

Ну хорошо. Стандарт С++03 в 1.5 больше стандарта последнего С#. Но это, разумеется, тоже "только подтверждает" твои слова.

AVK>>>Заявление сделал ты, а не я. Оно процитировано выше.

ВВ>>Повторюсь, мне неинтересно спорить о том, что такое мейнстрим.
AVK>Так не спорь.

В следующий раз, пожалуй, так и поступлю.

ВВ>> Если этот термин вызывает различные трактовки, не проще ли переформулировать свою изначальную мысль
Автор: AndrewVK
Дата: 17.07.12
?

AVK>Мне проще просто бросить с тобой общаться в очередной раз.

Ну конечно, когда тебя просят уточнить свою мысль и сказать конкретно, в каких промышленных областях не будет ФЯ, то проще бросить общаться — ведь тут демагогией заниматься уже не получится.
Давай в следующий раз ты и не будешь начинать, ладно? Тогда, возможно, мне ответит тот, кому есть что сказать.
Re[19]: Зачем нужно наследование интерфейсов?
От: AlexRK  
Дата: 18.07.12 06:17
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, AlexRK, Вы писали:


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


VD>Только пока есть динамические данные будут и ошибки времени выполнения.


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

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


Это все верно. Но это вопрос неразвитости технологии.
Кстати, уже сейчас есть такие штуки, как Ada SPARK, или Perfect Developer, где не так уж страшно все выглядит. Хотя, конечно, до мейнстрима еще очень далеко. Вот пара ссылок:
http://www.eschertech.com/product_documentation/LanguageIntroduction.htm
http://www.eschertech.com/tutorial/tutorials.php

VD>И самое смешное — большая часть рантайм-ошибок никогда не встретятся на практике. А стало быть усилия будут потрачены на практике.


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

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


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

К примеру, в коде
  number MyFunc(number arg)
  {
    return (arg + 1);
  }

нет никаких утверждений, но компилятор выводит их сразу несколько:
1) область определения arg не определена — функция может быть вызвана для любого типа числа (Int32, Int64, etc.);
2) результат функции больше аргумента на единицу (банально, но тем не менее — где может возникнуть переполнение, придется ставить проверку);
3) функция не имеет побочных эффектов.

В общем, идея примерно такая. ИМХО, в этом направлении все будет постепенно двигаться.

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


Тут ничего не могу сказать, не копенгаген в этом вопросе.
Re[17]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 18.07.12 08:01
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>На мой взгляд в чистом виде они никогда не попадут в мэйнстрим. Бессмысленно делать язык для программирования без побочных эффектов на в доску императивном компьютере.


Чистые ФЯ не являются языками "без побочных эффектов" — это заблуждение. Это языки, предлагающие инструментарий контроля за побочными эффектами. В других языках такого инструментария нет.

VD>Многие задачи по смыслу императивны и эмуляция их на чем-то вроед монад приведет к усложнению, а не к упрощению.


По смыслу императивные задачи можно решать императивно — это не проблема. Любые императивные инструменты в чистых ФЯ доступны, но не наоборот.

VD>Но часто фишки ФП могут упростить задачу. Так что смесь ФП и МП будет только развиваться.


Ну я и не спорю с этим — будут развиваться. В языке с нормальной системой типов разницы между обычным и МП кодом вообще нет.

VD>Когда мэйнстрим полностью впитает ФП, то говорить о чистых ФЯ просто не придется.


Конечно впитает, а потом ООП фичи отомрут как устаревшие и мешающие прогрессу языков.

VD>Второй раз слышу это словосочетание. Гугль ничего не объясняет. Что это значит?


Total functional programming.

VD>Я ставлю на ДСЛ-и и МП. А ФП, ООП будут позволять упростить генерацию кода для них.


Не вижу, как ООП может упростить МП — по моему, может только усложнить.

VD>Паровые машины (Лисп) не предлагать. Не тот уровень юзабельности.


Уж Лисп я точно предлагать никогда не буду.

VD>Ты явно не из числа тех кого можно к мэйнстриму отнести. Тебе и еще кому-то нужны. Но людям в целом — нет. Уровень решения задач все равно крайне низкий.


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

VD>Мозголомство страшное. Не взлетит.


Мозголомство там с непривычки, разве что. Я, как человек ленивый и медленно соображающий — как раз за простоту ФП и люблю.

VD>А вот ФП-шные фишки в мэйнстрим впитаются. Лямбды уже тут. Паттерн-матчингу пока мэйнстрим сопротивляется, но в течеии лет 10 сдастся.


В случае ФП, лямбды и ПМ — это только вершина айсберга. Главная фишка тех же АлгТД — совсем не ПМ, а то, что они алгебраические — т.е. кучу полезного кода, который с ними работает можно просто вычислить автоматически, а не придумывать (превращает метапрограммирование из шаманства в более чем простое занятие), а промежуточные значения просто стереть без остатка — и также автоматически (помогает производительности). Те, что нельзя стереть, раз уж они не только промежуточные, а хранят разделяемый результат — можно автоматически "сплющить" из графа объектов в плоские структуры, уменьшив промахи мимо кеша, снизив нагрузку на ГЦ и т.д. Наивный прототип кода с ними можно преобразовать в более сложный, но эффективный (полуавтоматически, как решение уравнений во всяких Мейплах и Математиках), как ряд простых преобразований, а каждое преобразование — проверить на правильность автоматически. С объектами ничего из этого нельзя сделать в принципе. (Ну, "сплющивание" для простых случаев и в рантайме, а не статически — можно сделать)
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[16]: AlexRK
От: AlexRK  
Дата: 18.07.12 08:13
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Здравствуйте, AlexRK, Вы писали:


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


K>Если подумать, где еще используется сабтайпинг — то эти места очевидны. Гетерогенные списки, например. При сабтайпинге мы можем иметь массив IPet[], хранящий классы Cat и Dog. Если сабтайпинга нет — массив будет типа {exist T where T : IPet}[].


Кстати да, вы совершенно правы. Отличная идея.
Re[20]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 18.07.12 11:31
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Здравствуйте, Воронков Василий, Вы писали:

ВВ>>Мне кажется, тут следует вначале задать другой вопрос — а что *нужно* мейнстриму?
K>Мейнстриму нужны инструменты решения задач, на которые есть спрос.

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

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

K>"Доменный" язык — это просто библиотека с удобным интерфейсом. Нужны будут средства для их разработки.

Это лишь одно из пониманий DSL.
Другое — язык программирования, заточенный под конкретную предметную область, НЕ внутренний DSL.
Средства для их разработки, конечно, нужны, но я разработку средств разработки к мейнстримным задачам не отношу. Кстати, в эту сферу ФЯ почти уже пришли. Ну или уж по крайней мере их тут использовать совершенно ничто не мешает.

ВВ>>Т.о. программирование превращается скорее в этакую "конфигурацию" софта. Тенденция такая, однако, намечается.

K>В этом ничего нового нет. Многие задачи, которые сейчас решаются "конфигурацией софта" — раньше решались программистами. Но мейнстрим не стал конфигурацией софта, т.е. не перестал быть программированием. Просто мейнстрим стал решать другие проблемы. А когда и они начнут решаться конфигурацией софта — все еще будет решать другие. Задач для программистов меньше не станет.

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

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

Например:
системные вещи
графика
разработка игр
финансы (ну тут почти пришли)
веб (?)
...
Re[20]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 18.07.12 11:46
Оценка:
Здравствуйте, Klapaucius, Вы писали:

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

K>Во-первых, для ООП и ФЯ нужны разные системы типов. Их сочетание порождает мозгоразрывающие явления вроде системы типов Scala да еще и с обязательными сигнатурами типов повсюду, которые чуть попроще сигнатур Агды 2 (да и то не факт, что попроще).
K>Альтернатива разрыву мозга — "марсианское" ООП, вроде того, что в ОКамле (ничего плохого в нем, в принципе, нет, но мейнстримному ООП программисту оно также чуждо, как и ФП.)
K>Во-вторых, ФЯ и ООЯ требуют разных рантаймов и, в частности, разных (как минимум — настоек) сборщиков мусора.
K>Т.е. и на уровне дизайна языка, и на уровне реализации нужно сидеть на двух стульях — что не очень удобно.

В каком-то смысле "гибридным" можно считать такой ФЯ, в котором есть средства, позволяющие в некотором смысле имитировать ООП.
Скажем, при наличии тайпклассов и экзистенциалов мы вполне можем получить рантайм полиморфизм, эквивалентный ООП.
Чем не гибрид?
Re[21]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 18.07.12 12:43
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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

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

Это будет упомянутое мной выше "марсианское" ООП.
Под гибридом же понимается, как я понимаю, ситуация: "хочу чтоб все осталось по-старому, только поверх добавились все фичи ФП". Это невозможно. Возможна ситуация "хочу чтоб все осталось по-старому, только поверх добавились бы кое-какие (очень немногие) фичи ФП". А дальше уже трейдофф между тем что остается по-старому и фичами ФП. Если принимаются все фичи ФП — по старому ничего не остается. Ну или остается кое-что, очень немногое.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[22]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 18.07.12 12:59
Оценка:
Здравствуйте, Klapaucius, Вы писали:

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

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

K>Это будет упомянутое мной выше "марсианское" ООП.

K>Под гибридом же понимается, как я понимаю, ситуация: "хочу чтоб все осталось по-старому, только поверх добавились все фичи ФП". Это невозможно. Возможна ситуация "хочу чтоб все осталось по-старому, только поверх добавились бы кое-какие (очень немногие) фичи ФП". А дальше уже трейдофф между тем что остается по-старому и фичами ФП. Если принимаются все фичи ФП — по старому ничего не остается. Ну или остается кое-что, очень немногое.

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

Так что, кто бы ни победил, победят "гибридные" языки
Re[23]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 18.07.12 13:34
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


ВВ>Так что, кто бы ни победил, победят "гибридные" языки


Рациональное зерно в этом есть, но если так рассуждать, то окажется что все языки гибридные и только и делают что побеждают другие гибридные языки. Но "гибриды" которые тут обсуждаются — обсуждаются не в первый раз и известно что именно под этим словом понимают те, кто его употребляют. А понимают они "мейнстримный ООЯ (база) с добавленными элементами ФП (надстройка)". Хаскель, очевидно, таковым не является, а Скала — является.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[12]: Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 18.07.12 14:58
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Кстати, "наследование" тайпклассов в хаскеле — фича сомнительной полезности, да еще и, в некоторых случаях, достаточно проблемная.

K>Почему сомнительной полезности? И почему проблемная?
K>Члены тайпкласса "наследника" редко могут быть реализованы в терминах базового класса (тут наследование могло бы помочь), но зато очень часто базовый класс может быть реализован в терминах наследника (тут наследование ничем помочь не может). Возможно, полезность наследованию могли бы придать так называемые дефолтные реализации для суперклассов:
K>
K>class Functor f => Applicative f where
K>    return :: x -> f x
K>    (<*>) :: f (s -> t) -> f s -> f t
K>    (>>) :: f s -> f t -> f t
K>    fs >> ft = return (flip const) <*> fs <*> ft
K>    -- описываем дефолтный инстанс для суперкласса.
K>    instance Functor f where
K>        fmap = (<*>) . return
        
K>class Applicative f => Monad f where
K>    (>>=) :: f a -> (a -> f b) -> f b
K>    instance Applicative f where
K>        ff <*> fs = ff >>= \f -> fs >>= \s -> return (f s)
K>


Здесь, собственно, какой момент. Вот "большевики" долго говорят о том, что монада должна быть апликативным функтором. Вернее, даже не так. Монада *является* апликативным функтором. Возникает естественное желание это самое "является" как-то зафиксировать. Наследование — как раз способ подобной фиксации. И теперь, собственно, вопрос. А что мы теряем, если на уровне абстракции подобной фиксации не будет? Т.е. понятно, что сейчас ее и так нет. Но все же — есть ли какие-то *реальные* проблемы из-за этого?

Одна проблема мне понятна (кстати, не понимаю, как тут помогут те же default-ы) — реализуя Монаду, я не могу получить реализацию того же функтора "из коробки", мне придется ее-таки описать (да, я могу описать ее через готовые функции, но это-таки бойлерплейт). Эту проблему могли бы решить как раз "дефолтные реализации для суперклассов". Или даже без них — сама монада (ну при наличии немного другой, более "православной" иерархии классов) могла бы быть описана в терминах map/join — таким образом, я бы реализовал map/join, а реализацию монады получил бы за бесплатно. Без наследования же — только бойлерплейт (?)

А что еще?

K>Наследование, в принципе, позволяет избавиться от огромных контекстов. Но на практике для этого используется редко (городить такую сильную связь ради некоторого уменьшения писанины — спорное решение). Тем более, что в современном хаскеле есть средства куда луше:

K>
K>type NumAndEq a = (Num a, Eq a)
K>foo :: NumAndEq a => a -> a -> Bool
K>foo a b = a * b == a
K>

K>Т.е. в хаскеле сейчас тенденция такая: отказ от наследования в стандартных библиотеках, добавление более адекватных (это, впрочем, еще время покажет — или не покажет) средств решения проблем без всякого наследования.

А нет каких-либо тредов или тикетов на тему "а давайте выпилим наследование"? Было бы интересно почитать.
Re[13]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 23.07.12 09:03
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здесь, собственно, какой момент. Вот "большевики" долго говорят о том, что монада должна быть апликативным функтором. Вернее, даже не так. Монада *является* апликативным функтором. Возникает естественное желание это самое "является" как-то зафиксировать. Наследование — как раз способ подобной фиксации.


Да, тут фиксация безвредна, потому что достоверно известно, что для всего, для чего можно написать инстанс монады — можно и интсанс аппликативного функтора написать. Это, однако, скорее исключение: в большинстве случаев никакой уверенности в том, что при возможности реализовать класс C можно реализовать и суперкласс S нет. А это порождает проблемы аналогичные всяким интерфейсным методам, выбрасывающим NotImplementedException. К примеру, имплементация Num для функций из чисел в числа вполне имеет смысл и может быть написана, но реализации Show и Eq — нет. "Наследование" вынуждает их писать.

ВВ>И теперь, собственно, вопрос. А что мы теряем, если на уровне абстракции подобной фиксации не будет? Т.е. понятно, что сейчас ее и так нет. Но все же — есть ли какие-то *реальные* проблемы из-за этого?


Проблемы вполне были, но не особенно серьезные. Дело в том, что если что-то можно не написать — его и не напишут. Например, долгое время не было имплементации Applicative для ST. Это вызывало некоторые неудобства. Есть, конечно, обертки, превращающие любой инстанс Monad в инстанс Applicative, но они замусоривают код. Кроме того, теоретически можно реализовать Applicative и Monad по разному — а это уже хитрый баг. Наследование тут, правда, не сильно поможет, разве что тем, что сократит время между реализациями (в нашем случае инстанс Monad писали, допустим, в 1995, a Applicative — в 2005).

Вообще, несуществующая в Prelude иерархия Functor -> Applicative -> Monad сама по себе является демонстрацией проблем "наследования". Суперкласс трудно добавить позднее. Даже если такую иерархию поправить — рано или поздно появится какой-нибудь Pointed (между Functor и Applicative). Особая ирония в том, что иерархия эта фундаментальна, известна была за годы до появления хаскеля и достоверно свободна от проблем типа наследования Num от Eq. Но даже в этих тепличных условиях "наследование" подвело. С подавляющим большинством других иерархий проблем будет только больше.

ВВ>Одна проблема мне понятна (кстати, не понимаю, как тут помогут те же default-ы) — реализуя Монаду, я не могу получить реализацию того же функтора "из коробки", мне придется ее-таки описать (да, я могу описать ее через готовые функции, но это-таки бойлерплейт). Эту проблему могли бы решить как раз "дефолтные реализации для суперклассов". Или даже без них — сама монада (ну при наличии немного другой, более "православной" иерархии классов) могла бы быть описана в терминах map/join — таким образом, я бы реализовал map/join, а реализацию монады получил бы за бесплатно. Без наследования же — только бойлерплейт (?)


Ну так "наследование" тут как раз не особенно помогает, о чем я и писал. А default-реализации помогают. Сравните сами:
-- нет "наследования" и default-методов:
instance Functor F where
    fmap = ...
    
instance Applicative F where
    pure = ...
    (<*>) = ...
    
instance Monad F where
    return = ...
    (>>=) = ...
-- реализуем пять функций.

-- теперь исправленная иерархия с "наследованием":
instance Functor F where
    fmap = ...
    
instance Applicative F where
    pure = ...
    (<*>) = ...
    
instance Monad F where
    join = ...

-- реализуем четыре функции. При этом join не сильно легче bind, так что
-- наследование спасло нас только от повторной реализации pure/return 
-- самой простой из четырех.

-- А теперь варианты с default-ами:

instance Functor F -- эти инстансы не обязательны.

instance Applicative F -- в отличие от случая с "наследованием".

instance Monad F where
    return = ...
    (>>=) = ... -- либо join, зависит от того, как класс определили.
    
-- реализуем две функции.
-- если же у нас уже есть готовые инстансы Functor и Applicative
-- что, само по себе, явление редкое (Functor можно вывести автоматически, Applicative - нет)
-- то все будет как при "идеальной иерархии"
-- return повторно реализовывать не нужно.


ВВ>А нет каких-либо тредов или тикетов на тему "а давайте выпилим наследование"? Было бы интересно почитать.


"Наследование" как фичу? Нет, никто его "выпиливать" не собирается. Все-таки это наследование в кавычках — аналогом наследования является в самом простом случае. На самом деле это контексты, аналог констрейнтов дженериков, в более интересных случаях наследованию не эквивалентны, и претензии к "сомнительной полезности" к контекстам в общем случае не применимы. Например:
class (Monad m, Monad (t m)) => Trans t m where
-- или там
class (FunDep a ~ b) => C a b where type FunDep a

Тут уже с наследованием мало общего.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[2]: Зачем нужно наследование интерфейсов?
От: Klapaucius  
Дата: 23.07.12 11:11
Оценка:
Здравствуйте, PSV100, Вы писали:

PSV>В этой ветке
Автор: Temoto
Дата: 06.07.12
начали говорить о Go, но не договорили. Интерфейсы у него, фактически, аналог классов типов в Хаскеле или протоколов и типов в Кложуре и т.п.:


PSV>
PSV>type Reader interface {
PSV>    Read(b []byte) (n int, err error)
PSV>}

PSV>type Writer interface {
PSV>    Write(b []byte) (n int, err error)
PSV>}

PSV>type ReadWriter interface {
PSV>    Reader
PSV>    Writer
PSV>}
PSV>


PSV>Фактически, это аналог хаскелевских деклараций вида:


PSV>class (Eq a, Show a) => C a where ...


И близко не аналог. Принципиальное отличие выделено жирным шрифтом. Как, например, на го-интерфейсах делается упомянутый вами класс Eq?
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.