Зачем нужно наследование интерфейсов?
От: Воронков Василий Россия  
Дата: 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: Зачем нужно наследование интерфейсов?
От: 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[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]: Зачем нужно наследование интерфейсов?
От: fddima  
Дата: 06.07.12 20:17
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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

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

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

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

GetItems? Там вообще непонятно, зачем возвращать интерфейс. Это же не полиморфный метод, он вполне конкретную штуку возвращает. Если метод полиморфный, то нужные интерфейсы просто навешиваются в констрейнтах.
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[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)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.