Здравствуйте, AndrewVK, Вы писали:
AVK>Я, честно говоря, мог попутать Go с чем то еще на гугле. В том языке, про который речь, вроде бы были встроенные в него миксины.
Интересно с чем? В Гоу вроде бы их не было. Хотя может это я ошибаюсь.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, 0x7be, Вы писали:
0>Что если принципиально разделить эти вещи? Абстракция через обобщение в чистом виде есть во многих языка в виде интерфейсов, которые, кстати, поддерживают множественное наследование даже там, где классы поддерживают только единичное. Повторное использование кода тоже возможно другим способом — через композицию объектов. Единственное, чего нет — это синтаксически хорошо оформленное делегирование реализации интерфейса/части интерфейса композитам, из которых составлен класс-композиция. Но это не сложный аспект, который можно реализовать.
Тот же delphi поддерживает implementing interfaces by delegation c 1998 года (с delphi 4.0). Аналогичную возможность обещали в c# 4.0
0>Что если принципиально разделить эти вещи? Абстракция через обобщение в чистом виде есть во многих языка в виде интерфейсов, которые, кстати, поддерживают множественное наследование даже там, где классы поддерживают только единичное. Повторное использование кода тоже возможно другим способом — через композицию объектов. Единственное, чего нет — это синтаксически хорошо оформленное делегирование реализации интерфейса/части интерфейса композитам, из которых составлен класс-композиция. Но это не сложный аспект, который можно реализовать.
Здравствуйте, AndrewVK, Вы писали:
AVK>Я, честно говоря, мог попутать Go с чем то еще на гугле. В том языке, про который речь, вроде бы были встроенные в него миксины.
Здравствуйте, AndrewVK, Вы писали:
FR>>Скорее всего с D попутал.
AVK>В D нет наследования реализации?
Одиночное есть, множественного нет, для интерфейсов множественное есть.
Но при тех средствах что в нем доступны миксины, алиасы this и диспетчеризации вызовов, можно при желании легко обойтись без наследования вообще
Здравствуйте, Caracrist, Вы писали:
C>Пишешь такие методы на интерфейсы и наследуешь сколько хочешь и по сколько хочешь раз.
Extensions Methods — это синтаксический сахар, *весь* смысл которого заключается в том, что он позволяет вместо
MyHelper.DoSomething(foo);
писать
foo.DoSomething();
При этом DoSomething по-прежнему внешний статический метод, не имеющий доступа к деталям реализации Foo, а со структурами вы так еще и лишнее копирование получите.
Причем у Extensions Methods есть и немало минусов — например, очень плохо discoverability функциональности.
Здравствуйте, Yuki-no Tenshi, Вы писали:
0>>Вот и я о том же. Но если ручное делегирование заменить специальным механизмом, позволяющим делегировать композиту реализацию интефеса/его части, то подобной проблемы не будет.
YNT>Можно пример( допустим, на некоем псевдокоде) работы описанного вами механизма? Или это утверждение что-то вроде "хорошо бы чтобы был мир во всем Мире"
Если я правильно понял чего хочет автор, то это действительно старая шировко известная в узких кругах вещь (потому, думаю и не пошла пока в широкие массы, что про аггрегацию и делегирование ширпотребных книг мало, а про наследование — в любом учебнике "С? за пять дней")
И выглдяит желаемое примерно так:
interface IVehile
{
void Move();
}
interface IGun
{
void Fire();
}
class Car : IVehile
{
public void Move()
{
//some implementation
}
public void OtherMethod(){}
public void AndOneMoreNotIntrestingMethod(){}
}
class Gun : IGun
{
public void Fire()
{
//some implementation
}
}
public class Tank: IVehile, IGun
{
[TakeMethod( Move )]private Car _chassis; //теперь у класса Tank есть собственный метод Move, взятый из класса Car. Можно вызывать tank.Move();[TakeMethod( Fire )]private Gun _gun; //теперь у класса Tank есть собственный метод Fire, взятый из класса Gun. Можно вызывать tank.Fire();
//но можно комбинировать и не напряму, а как в обычной агрегацииpublic void LocateAndDestroy()
{
//IsTargetLocated & SearchTarget - реализованы тоже в этом классе каким-то там способом,
// включая возможное собственное внутреннее состояниеwhile( !IsTargetLocated )
{
_chassis.Move();
SearchTarget();
}
_gun.Fire();
}
}
//никто однако не мешает сделать то же и без агрегирования любого из имеющихся объектовpublic class LaserTank: IVehile, IGun
{
[TakeMethod( Move )]
private Car _chassis;
public void Fire()
{
//Implement Laser Fire
}
}
//или можно использовать метод не целиком как есть а как часть (аналог вызова base.Method):public class RoadBuildingTank: IVehile, IGun
{
private Car _chassis;
[TakeMethod( Fire )]
private Gun _gun;
public void Move()
{
BuildRoadAtFront();
_chassis.Move();
DestroyRoadAtBehind();
}
}
//одно из очевидных применений передавать объекты-агрегаты как параметры.
//В результате получим динамически создаваемые классыclass Tank : IVehile, IGun
{
[TakeMethod( Move )]
private ICar _chassis;
[TakeMethod( Fire )]
private IGun _gun;
public Tank( IVehile chassis, IGun gun )
{
_chassis = chassis;
_gun = gun;
}
}
//использованиеvar tank = new Tank( new TracksVehile(), new Gun() );
tank.Move();
tank.Fire();
var laserTank = new Tank( new TracksVehile(), new Laser() );
laserTank.Move();
laserTank.Fire();
var infantrySupport = new Tank( new Car(), new MachineGun() );
Проблема (или достоинство, это еще как посмотреть) такого подхода — отсутствие доступа к приватным членам интегрируемого класса.
Проблема — потому что уменьшаются возможности переиспользования кода
ДОстоинство — потому что уменьшается так же и связность, меньше шансов ошибиться (хотя, конечно, копи-паст тоже не путь к надежному коду )
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, 0x7be, Вы писали:
0>>Мне тут люди возражают, так что не все дело в рынке Просто это традиция такая, если ООП — значит три кита и все такое. Как и любая другая традиция, эта закрепилась просто в силу человеческой природы
VD>Ты плохо знаешь человеческую природу. Человеческое мнение это в 99% случаев то, что ему вдували. Чем дольше вдували, тем крепче мнение.
Так он вобщем-то про то и говорит. Много вдули — закрепилась традиция. И теперь новый ООП-язык без наследования поведения широкая аудитория воспримет как минимум странно.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Extensions Methods — это синтаксический сахар, *весь* смысл которого заключается в том, что он позволяет вместо
ВВ>
ВВ>MyHelper.DoSomething(foo);
ВВ>
ВВ>писать
ВВ>
ВВ>foo.DoSomething();
ВВ>
Это не совсем так (хотя и не относится к обсуждаемой теме). Попробуй переписать следующий код без extension methods без добавления вспомогательных конструкций:
using System;
using System.Linq;
class C
{
Func<int> f = "".Count;
}
Здравствуйте, nikov, Вы писали:
ВВ>>Где здесь магия? Все то же самое можно представить в виде обычного метода. N>Но нельзя создать делегат.
Почему нельзя?
public static Func<Int32> Count<TSource>(this IEnumerable<TSource> source)
{
Func<Int32> f = () => {
if (source == null)
{
//throw Error.ArgumentNull("source");
}
ICollection<TSource> is2 = source as ICollection<TSource>;
if (is2 != null)
{
return is2.Count;
}
int num = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
num++;
}
}
return num;
};
return f;
}
Строка имеет интерфейс IEnumerable<Char>. Через этот интерфейс мы можем делать все что нам хочется — в т.ч. и считать кол-во чаров по условию, например. Какие тут дополнительные возможности дает extension method?
Здравствуйте, Воронков Василий, Вы писали:
ВВ> Какие тут дополнительные возможности дает extension method?
Создать делегат типа Func<int> к методу с сигнатурой int Count(IEnumerable<char>) без вспомогательных анонимных функций и явного вызова CreateDelegate.
Здравствуйте, nikov, Вы писали:
ВВ>> Какие тут дополнительные возможности дает extension method? N>Создать делегат типа Func<int> к методу с сигнатурой int Count(IEnumerable<char>) без вспомогательных анонимных функций и явного вызова CreateDelegate.
Извини, я снова не понимаю. А что мешает-то?
public static int MyCount<TSource>(IEnumerable<TSource> source)
{
var is2 = source as ICollection<TSource>;
if (is2 != null)
return is2.Count;
var num = 0;
foreach (var c in source)
num++;
return num;
}
var f = new Func<IEnumerable<Char>,Int32>(MyCount);
Выглядит это, конечно, менее красиво. Ну так сахар на то и сахар, я совершенно не против extension methods, а очень даже за.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, nikov, Вы писали:
ВВ>>> Какие тут дополнительные возможности дает extension method? N>>Создать делегат типа Func<int> к методу с сигнатурой int Count(IEnumerable<char>) без вспомогательных анонимных функций и явного вызова CreateDelegate.
ВВ>Извини, я снова не понимаю. А что мешает-то?
ВВ>
ВВ>var f = new Func<IEnumerable<Char>,Int32>(MyCount);
ВВ>
Ну посмотри внимательно: у тебя делегат типа Func<IEnumerable<Char>,Int32>, то есть он принимает параметр IEnumerable<Char>. А надо создать делегат Func<int> (не принимающий параметров) к тому же методу, передав аргумент при создании делегата.