Потом вспоминаем, что при чтении бывают ошибки, меняем сигнатуру ByteReader/Writer, изменения автоматически расползлись по всем унаследованным интерфейсам.
T>Потом вспоминаем, что при чтении бывают ошибки, меняем сигнатуру ByteReader/Writer, изменения автоматически расползлись по всем унаследованным интерфейсам.
Честно, я не понял пример. File наследуется от ByteReader/ByteWriter? Как-то это... странно
Ну положим, эта цепочка наследования валидна. Мне здесь непонятно две вещи:
1) Как это помогает автоматическом "расползанию" изменений? Сейчас у тебя некий метод работает с абстракцией IFile. Без наследования он будет работать с абстракцией (IByteReader IByteWriter IFile) — если ему действительно нужно все это барахло. Ну и в чем профит?
2) А вот проблему потенциальную я вижу. Интерфейсы закрыты, и если IFile писали не мы, то отнаследовать его от IByteReader ты уже не сможешь. Поэтому в таком случае ты просто создашь отдельный интерфейс IByteReader — и дальше см. п. 1. В тех случаях, когда ты пишешь все сам, ты-таки отнаследуешь. И итоговая картина получается какой-то... несимметричной.
ВВ>Честно, я не понял пример. File наследуется от ByteReader/ByteWriter? Как-то это... странно
ВВ>Ну положим, эта цепочка наследования валидна. Мне здесь непонятно две вещи:
ВВ>1) Как это помогает автоматическом "расползанию" изменений? Сейчас у тебя некий метод работает с абстракцией IFile. Без наследования он будет работать с абстракцией (IByteReader IByteWriter IFile) — если ему действительно нужно все это барахло. Ну и в чем профит?
Как это помогает: меняем интерфейс Reader, автомагически изменился File и NetworkConnection. Вот такое свойство данной системы типов. Ничего ни с чем не сравниваю и не предлагаю.
Если система типов позволяет функции open вернуть безымянное объединение интерфейсов ByteReader+Writer+File — это круто. Я пока такого не видел, видел только возможность вернуть один именованый тип.
ВВ>2) А вот проблему потенциальную я вижу. Интерфейсы закрыты, и если IFile писали не мы, то отнаследовать его от IByteReader ты уже не сможешь. Поэтому в таком случае ты просто создашь отдельный интерфейс IByteReader — и дальше см. п. 1. В тех случаях, когда ты пишешь все сам, ты-таки отнаследуешь. И итоговая картина получается какой-то... несимметричной.
Отнаследовать существующий тип — эту фразу я вообще не понимаю. Мне логично любой чужой тип рассматривать как неизменяемый.
Здравствуйте, Temoto, Вы писали:
T>Как это помогает: меняем интерфейс Reader, автомагически изменился File и NetworkConnection. Вот такое свойство данной системы типов. Ничего ни с чем не сравниваю и не предлагаю.
Ну мы же рассматриваем это с позиции нужно/не нужно. Вот зачем автоматически менять *интерфейсы* File и NetworkConnection? Сами же эти интерфейсы не поменялись. По-моему это вообще скорее плохо.
T>Если система типов позволяет функции open вернуть безымянное объединение интерфейсов ByteReader+Writer+File — это круто. Я пока такого не видел, видел только возможность вернуть один именованый тип.
Как это не видел? В том же шарпе да и джаве это делается через генерики легко и просто. Причем это языки с не самой навороченной системой типов.
ВВ>>2) А вот проблему потенциальную я вижу. Интерфейсы закрыты, и если IFile писали не мы, то отнаследовать его от IByteReader ты уже не сможешь. Поэтому в таком случае ты просто создашь отдельный интерфейс IByteReader — и дальше см. п. 1. В тех случаях, когда ты пишешь все сам, ты-таки отнаследуешь. И итоговая картина получается какой-то... несимметричной. T>Отнаследовать существующий тип — эту фразу я вообще не понимаю. Мне логично любой чужой тип рассматривать как неизменяемый.
А чего тут понимать-то? Вот забыли разработчики какой-нибудь библиотеки добавить нужную тебе абстракцию. Скажем, интерфейс ICollection сделали, а вот какой-нибудь IMeasurable(Count) не сделали. Если бы ты писал с нуля, то отнаследовал бы ICollection от IMeasurable, а так не получится — придется довольствоваться двумя несвязанными интерфейсами. И такие ситуации — сплошь и рядом.
Здравствуйте, 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"
}
T>>Если система типов позволяет функции open вернуть безымянное объединение интерфейсов ByteReader+Writer+File — это круто. Я пока такого не видел, видел только возможность вернуть один именованый тип.
ВВ>Как это не видел? В том же шарпе да и джаве это делается через генерики легко и просто. Причем это языки с не самой навороченной системой типов.
Можно пример?
ВВ>>>2) А вот проблему потенциальную я вижу. Интерфейсы закрыты, и если IFile писали не мы, то отнаследовать его от IByteReader ты уже не сможешь. Поэтому в таком случае ты просто создашь отдельный интерфейс IByteReader — и дальше см. п. 1. В тех случаях, когда ты пишешь все сам, ты-таки отнаследуешь. И итоговая картина получается какой-то... несимметричной. T>>Отнаследовать существующий тип — эту фразу я вообще не понимаю. Мне логично любой чужой тип рассматривать как неизменяемый.
ВВ>А чего тут понимать-то? Вот забыли разработчики какой-нибудь библиотеки добавить нужную тебе абстракцию. Скажем, интерфейс ICollection сделали, а вот какой-нибудь IMeasurable(Count) не сделали. Если бы ты писал с нуля, то отнаследовал бы ICollection от IMeasurable, а так не получится — придется довольствоваться двумя несвязанными интерфейсами. И такие ситуации — сплошь и рядом.
Ты хочешь рассматривать открытые типы, когда я могу в чужую коллекцию добавить свою реализацию Count? Если нет, то я не понимаю почему речь идёт о чужом коде. Чужой код для меня закрыт, он обладает или не обладает нужными интерфейсами, но это невозможно изменить.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Воронков Василий, Вы писали: ВВ>>Собственно, сабж. Что это дает-то в принципе? AVK>Полиморфизм это дает. Который, в свою очередь, решает задачу динамической диспетчеризации по типу аргумента.
Ты точно понял о чем речь? Я говорю о наследовании интерфейсов, конкретно, о возможности интерфейс наследовать от других, а не о реализации интерфейсов.
Здравствуйте, Temoto, Вы писали:
ВВ>>Как это не видел? В том же шарпе да и джаве это делается через генерики легко и просто. Причем это языки с не самой навороченной системой типов. T>Можно пример?
C#:
T Something<T>(T val) where T : IFoo, IBar
{
...
}
ВВ>>А чего тут понимать-то? Вот забыли разработчики какой-нибудь библиотеки добавить нужную тебе абстракцию. Скажем, интерфейс ICollection сделали, а вот какой-нибудь IMeasurable(Count) не сделали. Если бы ты писал с нуля, то отнаследовал бы ICollection от IMeasurable, а так не получится — придется довольствоваться двумя несвязанными интерфейсами. И такие ситуации — сплошь и рядом. T>Ты хочешь рассматривать открытые типы, когда я могу в чужую коллекцию добавить свою реализацию Count?
Нет, не хочу.
T>Если нет, то я не понимаю почему речь идёт о чужом коде. Чужой код для меня закрыт, он обладает или не обладает нужными интерфейсами, но это невозможно изменить.
Ты пользуешься исключительно своими интерфейсами, которые сам же и пишешь? "Чужой код" может предоставлять не только реализации, но также и абстракции, которыми ты можешь пользоваться. А зачастую — которыми ты вынужден пользоваться. В абстракциях же часто присутствуют "дыры". Возможность наследования интерфейсов создает некие иерархии, в которые нельзя вклиниваться, если на каком-то уровне пропущена нужная тебе абстракция. Вот и приходится навешивать эти абстракции "снаружи".
Здравствуйте, DarkGray, Вы писали:
DG>в mainstream-языках это дает возможность статически проверять типы при возвращении интерфейса DG>если интерфейсы отнаследованы друг от друга DG>
DG>то функция возвращая ICollection, предоставит статически проверяемую возможность обратиться как к методам ICollection, так и к методам IEnumerable DG>
DG>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу
Что в этих мейнстрим языках уже решается через генерики
Нет, я понимаю, что "интерфейсы здесь были раньше". Т.е. если причины чисто исторические — ОК, такой ответ принимается. Вопрос, есть ли какие другие причины, кроме "а раньше мы по-другому не умели".
Здравствуйте, Воронков Василий, Вы писали:
DG>>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу ВВ>Что в этих мейнстрим языках уже решается через генерики
Как это решается через генерики?
Здравствуйте, fddima, Вы писали:
DG>>>то функция сможет вернуть только или IEnumerable, или ICollection, и придется явно кастить, чтобы получить доступ к другому интерфейсу ВВ>>Что в этих мейнстрим языках уже решается через генерики F> Как это решается через генерики?
GetItems? Там вообще непонятно, зачем возвращать интерфейс. Это же не полиморфный метод, он вполне конкретную штуку возвращает. Если метод полиморфный, то нужные интерфейсы просто навешиваются в констрейнтах.
Здравствуйте, AndrewVK, Вы писали:
ВВ>> Я говорю о наследовании интерфейсов, конкретно, о возможности интерфейс наследовать от других, а не о реализации интерфейсов. AVK>При чем тут реализация? Отнаследованный интерфейс ты можешь привести к базовому безопасно. Классический полиморфизм.
Ничего не понял. Зачем мне отнаследованный интерфейс приводить к базовому да еще "безопасно"? Зачем мне вообще приводить интерфейс к чему-либо?
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Собственно, сабж. Что это дает-то в принципе? На первый взгляд кажется, что это вообще скорее вредно.
// 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);
}
...
}