Re[7]: А вы используете массивы?
От: Qbit86 Кипр
Дата: 26.12.08 07:26
Оценка:
_FR>А почему не на MyCustomList<T> или MyCustomList2<T>? Или вместо них я должен IEnumerable<T> использовать?

Если твоя или библиотечная функция обходится IEnumerabl'ом, то можешь передать ей в качестве аргумента свои CustomList'ы (если они реализуют IEnumerable<T>).
Глаза у меня добрые, но рубашка — смирительная!
Re[6]: А вы используете массивы?
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 07:27
Оценка: +1
Здравствуйте, Qbit86, Вы писали:

_FR>>Так вот прям List<>? Не IList<>?


Q>IList<T> не нужен практически никогда (имхо). Если ты в своём коде используешь IList<T>, то скорее всего, его нужно заменить либо на IEnumerable<T> (если обращение по индексу никогда не используется, а используется только перечисление), либо на List<T> (если обильно используется случайный доступ по индексу, то лучше входной параметр функции фиксировать этой конкретной реализацией IList'а, чтобы пользователь функции не мог передать связный список и поиметь падение производительности).

Этот момент не до конца понятен. Пользователь смотрит не на название класса, а на его контракт. Если он передает реализацию, в которой [] требует O(N), то не имеет права ожидать высокой производительности.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: А вы используете массивы?
От: _FRED_ Черногория
Дата: 26.12.08 07:41
Оценка:
Здравствуйте, Qbit86, Вы писали:

_FR>>А почему не на MyCustomList<T> или MyCustomList2<T>? Или вместо них я должен IEnumerable<T> использовать?


Q>Если твоя или библиотечная функция обходится IEnumerabl'ом, то можешь передать ей в качестве аргумента свои CustomList'ы (если они реализуют IEnumerable<T>).


Ага, и что бы получить количество элементов в объекте типа IEnumerable<T> придётся пробежать по всему набору записей, вместо того что бы обратиться к уже готовому свойству?

А если требуется дать возможность изменять содержимое списка, и при этом как-то реагировать на изменения? Это совсем не укладывается в твою концепцию

IList<T> не нужен практически никогда … Если ты в своём коде используешь IList<T>, то скорее всего, его нужно заменить либо на IEnumerable<T> … либо на List<T>…

Я там выше уже давал ссылки на мнение самих авторов BCL о классе List<> (Why we don’t recommend using List&lt;T&gt; in public APIs). Оно тебя не убедило?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[7]: А вы используете массивы?
От: Qbit86 Кипр
Дата: 26.12.08 07:53
Оценка:
S>Этот момент не до конца понятен. Пользователь смотрит не на название класса, а на его контракт.

В этом случае List<T> в аргументе лучше отражает контракт, чем IList<T>. Если разработчик библиотечной функции в качестве аргумента принимает IList<T>, и активно использует случайный доступ по индексу, то ему придётся отражать это в комментариях или документации. Например:
/* Хотя эта функция и принимает IList<T>, но в действительности сюда нужно передавать не любую реализацию индексируемого списка,
а лишь ту, что обеспечивается константное время доступа.
Т. е. вероятнее всего вам придётся передать сюда List<T>, т. к. LinkedList<T> понизит скорость с константной до кубической,
ибо в функции есть тройной цикл. */
int SomeFunc(IList<T> list);

Этот же вариант говорит сам за себя, и в контракте явно отражает не только интерфейс, но и ожидаемое время:
int SomeFunc(List<T> list);


Первый вариант более гибкий, но эта гибкость избыточна. Чуть более чем 99.175% разработчиков никогда не будут писать своих коллекций, а будут использовать стандартные. Т. е. скорее всего, либо List<T>, либо LinkedList<T>. Если твой алгоритм не подразумевает работу с медленно-индексируемой коллекцией, то лучше указать это явно.

S>Если он передает реализацию, в которой [] требует O(N), то не имеет права ожидать высокой производительности.


Допустим, что рассуждая таким способом пользователь отказался от связного списка в пользу динамического массива. И получил падение производительности, так как на самом деле в функции редки обращения по индексу, но обильны вставки в середину. Если бы программист явно указывал контракт (куда входит не только интерфейс, но и временные асимптотики), и указал бы конкретные List<T> или LinkedList<T>, то этих вопросов удалось бы избежать.
Глаза у меня добрые, но рубашка — смирительная!
Re[8]: А вы используете массивы?
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 08:18
Оценка: +1
Здравствуйте, Qbit86, Вы писали:

S>>Этот момент не до конца понятен. Пользователь смотрит не на название класса, а на его контракт.


Q>В этом случае List<T> в аргументе лучше отражает контракт, чем IList<T>.

Нет. Я категорически против этого неправомерного предположения.

Q>Если разработчик библиотечной функции в качестве аргумента принимает IList<T>, и активно использует случайный доступ по индексу, то ему придётся отражать это в комментариях или документации.

Если разработчику библиотеки не нужен быстрый доступ по индексу, он отразит это в том, что будет требовать IEnumerable.
Потому что на нём можно реализовать O(N) для this[] самостоятельно. Это понятно?
Так что как только речь заходит об интерфейсе с индексером, подразумевается, что этот индексер работает за приемлемое для пользователя время.

Q>Первый вариант более гибкий, но эта гибкость избыточна. Чуть более чем 99.175% разработчиков никогда не будут писать своих коллекций, а будут использовать стандартные.


Q>Т. е. скорее всего, либо List<T>, либо LinkedList<T>.

Для интересу встань на IList<T> в рефлекторе, и нажми * на Derived Types. Это по поводу двух вариантов, которые тебе видятся.

Далее, из интересных фактов можно отметить, что, к примеру, SortedList<TKey, TValue>.Keys возвращает IList<TKey>.
Значит, в алгоритм, который требует List<T>, его результат уже не передать. Зачем эти мучения?
Q> Если твой алгоритм не подразумевает работу с медленно-индексируемой коллекцией, то лучше указать это явно.
Это и указывается запросом соответствующего интерфейса.

Q>Допустим, что рассуждая таким способом пользователь отказался от связного списка в пользу динамического массива. И получил падение производительности, так как на самом деле в функции редки обращения по индексу, но обильны вставки в середину. Если бы программист явно указывал контракт (куда входит не только интерфейс, но и временные асимптотики), и указал бы конкретные List<T> или LinkedList<T>, то этих вопросов удалось бы избежать.

Зато это породило бы массу других вопросов. В том числе, невозможно было бы скормить в эту библиотеку даже элементарный T[].
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: А вы используете массивы?
От: Qbit86 Кипр
Дата: 26.12.08 08:19
Оценка:
Q>>Если твоя или библиотечная функция обходится IEnumerabl'ом, то можешь передать ей в качестве аргумента свои CustomList'ы (если они реализуют IEnumerable<T>).

_FR>Ага, и что бы получить количество элементов в объекте типа IEnumerable<T> придётся пробежать по всему набору записей, вместо того что бы обратиться к уже готовому свойству?


Ты путаешь код самой функции и вызывающий код. Я сказал: «если твоя или библиотечная функция обходится IEnumerabl'ом...» Т. е. подразумевал, что библиотечной функции IEnumerabl'а достаточно. Если недостаточно (скажем, внутри функции требуется узнавать размер, обращаться по индексу, делать вставки), то функции вероятнее всего нужен не IEnumerable<T>, а конкретный контейнер. Конкретный контейнер создатель функции в этом случае должен выбрать сам (чаще всего), исходя из того, каких операций больше. Если он выберет IList<T>, то это будет не совсем корректная обобщённость, так как ему в комментариях придётся эту обобщенность урезать: «Не используйте эту функцию с коллекциями, предполагающими медленную индексацию» (что почти всегда равносильно «Используйте с List<T>, не используйте с LinkedList<T>»). Или «Не используйте эту функцию с коллекциями, предполагающими медленную вставку» (что почти всегда равносильно «Используйте с LinkedList<T>, не используйте с List<T>»).

_FR> :xz: Я там выше уже давал ссылки на мнение самих авторов BCL о классе List<> (Why we don’t recommend using List&lt;T&gt; in public APIs). Оно тебя не убедило?


Я знаю этого чувака, Криштофа Квалину, толковые вещи пишет. Заметь, там он про обычные массивы и про IList<T> ничего не говорит, обобщает сразу до Collection<T>. Мне чаще приходится сталкиваться с ещё более общим интерфейсом — IEnumerable<T>, поэтому я про него и написал. Если достаточно более общего контракта, зачем его сужать?

Ещё заметь, в функциях BCL часто используются обычные массивы, а к ним рассуждения Квалины относятся в той же степени. И тем не менее.

Да и в принципе, я во всех комментариях старался оговаривать, что не претендую на безусловную общность, старался всавлять «вероятнее всего», «имхо», «почти всегда», etc.
Глаза у меня добрые, но рубашка — смирительная!
Re[8]: А вы используете массивы?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.12.08 08:32
Оценка:
Здравствуйте, Qbit86, Вы писали:

S>>Этот момент не до конца понятен. Пользователь смотрит не на название класса, а на его контракт.


Q>В этом случае List<T> в аргументе лучше отражает контракт, чем IList<T>. Если разработчик библиотечной функции в качестве аргумента принимает IList<T>, и активно использует случайный доступ по индексу, то ему придётся отражать это в комментариях или документации. Например:

Q>
Q>/* Хотя эта функция и принимает IList<T>, но в действительности сюда нужно передавать не любую реализацию индексируемого списка,
Q>а лишь ту, что обеспечивается константное время доступа.
Q>Т. е. вероятнее всего вам придётся передать сюда List<T>, т. к. LinkedList<T> понизит скорость с константной до кубической,
Q>ибо в функции есть тройной цикл. */
Q>int SomeFunc(IList<T> list);
Q>

Q>Этот же вариант говорит сам за себя, и в контракте явно отражает не только интерфейс, но и ожидаемое время:
Q>
Q>int SomeFunc(List<T> list);
Q>


Q>Первый вариант более гибкий, но эта гибкость избыточна. Чуть более чем 99.175% разработчиков никогда не будут писать своих коллекций, а будут использовать стандартные. Т. е. скорее всего, либо List<T>, либо LinkedList<T>. Если твой алгоритм не подразумевает работу с медленно-индексируемой коллекцией, то лучше указать это явно.


ИМХО вопрос производительности не должен влиять на проектирование контрактов.

S>>Если он передает реализацию, в которой [] требует O(N), то не имеет права ожидать высокой производительности.

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

Q>Если бы программист явно указывал контракт (куда входит не только интерфейс, но и временные асимптотики), и указал бы конкретные List<T> или LinkedList<T>, то этих вопросов удалось бы избежать.

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

Вообще это попахивает преждевременной оптимизацией.
Re[9]: А вы используете массивы?
От: Qbit86 Кипр
Дата: 26.12.08 08:33
Оценка:
Q>>Если разработчик библиотечной функции в качестве аргумента принимает IList<T>, и активно использует случайный доступ по индексу, то ему придётся отражать это в комментариях или документации.

S>Если разработчику библиотеки не нужен быстрый доступ по индексу, он отразит это в том, что будет требовать IEnumerable.


Тогда он не сможет использовать модификацию коллекции, удаление, например.

S>Зато это породило бы массу других вопросов. В том числе, невозможно было бы скормить в эту библиотеку даже элементарный T[].


Сырые массивы я использую редко, только если приходят из какой-то функции. Если его надо передать дальше, то да, придётся преобразовать его в конкретную дженерик-коллекцию.
Глаза у меня добрые, но рубашка — смирительная!
Re[9]: А вы используете массивы?
От: Qbit86 Кипр
Дата: 26.12.08 08:41
Оценка:
G>Вообще с чего это в контракт входят временные асимптотики?

Поэтому я и использую разные термины — интерфейс и контракт. Контракт, имхо, более широкое понятие, и включает в себя временные гарантии. IList<T> — интерфейс, LinkedList<T> — контракт. Это не преждевременная оптимизация, а избежание преждевременной пессимизации; я не считаю миллисекунды или такты, я учитываю асимптотику.

G>временные асимптотики — деталь реализации.


Где-то тут близко — «Закон Дырявых Абстракций» Джоэля. Я не могу полностью абстрагироваться от реализации. Поэтому разработчики стандартной библиотеки и предоставили разные реализации для одних и тех же интерфейсов.
Глаза у меня добрые, но рубашка — смирительная!
Re[10]: А вы используете массивы?
От: _FRED_ Черногория
Дата: 26.12.08 08:45
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>>>Если твоя или библиотечная функция обходится IEnumerabl'ом, то можешь передать ей в качестве аргумента свои CustomList'ы (если они реализуют IEnumerable<T>).


_FR>>Ага, и что бы получить количество элементов в объекте типа IEnumerable<T> придётся пробежать по всему набору записей, вместо того что бы обратиться к уже готовому свойству?


Q>Ты путаешь код самой функции и вызывающий код.


Я лишь прочитад твои слова. Если ты выразил свою мысль у'же, чем это можно понять, то "невиноватая я"

Q>Я сказал: «если твоя или библиотечная функция обходится IEnumerabl'ом...» Т. е. подразумевал, что библиотечной функции IEnumerabl'а достаточно.


Ты сказал

Если ты в своём коде используешь IList<T>, то скорее всего, его нужно заменить либо на IEnumerable<T> (если обращение по индексу никогда не используется, а используется только перечисление), либо на List<T> (если обильно используется случайный доступ по индексу, то лучше входной параметр функции фиксировать этой конкретной реализацией IList'а, чтобы пользователь функции не мог передать связный список и поиметь падение производительности).

без каких либо оговорок

Если ты просто неточно выразился или я тебя неправильно понял, то ОК.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[10]: А вы используете массивы?
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 08:52
Оценка:
Здравствуйте, Qbit86, Вы писали:
Q>Тогда он не сможет использовать модификацию коллекции, удаление, например.
А зачем ему модификация? В большинстве случаев модификация не нужна. Если нужна, то скорее всего, опять же, будет нужен вовсе не IList<T>, а что-то более другое.
Например, IDictionary либо какой-то интерфейс с void Add(T). Пока мне сложно представить реалистичный пример.


Если алгоритм использует специфику конкретного List<T> — тогда конечно да, можно его и потребовать. Но как правило этого не требуется, и ограничивать интерфейс конкретным классом — свинство.

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

Ну и зачем это делать? Вот это преобразование — оно что тебе даёт? Просад производительности, малозаметный на общем фоне? Лишнюю строчку кода?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: А вы используете массивы?
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.12.08 08:55
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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


Все описанное является следствием используемой платформы и/или языка.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: А вы используете массивы?
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 26.12.08 08:59
Оценка:
Здравствуйте, Mamut, Вы писали:

M>А как часто вы используете массивы?


Постоянно.

Для наборов данных постоянной длины занимающих ощутимое количество памяти альтернатив обычно и нет.

Многие алгоритмы наиболее эффективно работают на массивах. Часто быстрее превратить список в массив, обработать его, и превратить обратно, чем работать непосредственно со списком.
Ce n'est que pour vous dire ce que je vous dis.
Re[2]: А вы используете массивы?
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.12.08 09:04
Оценка:
Здравствуйте, samius, Вы писали:

S>А тут прибежали дотнетчики, которые привыкли списком обзывать List<T>, который на самом деле вектор а не список, т.к. имеет константное время доступа


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

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

Все это является ассоциацией конкретики с абстрактным названием.

Пожалуй, что самым разумным был подход Явы где имена типам коллекций давались по принципу приклеивания к информации о реализации типа интерфейса. Например, ArrayList означает, что это реализация интерфейса List на базе массива.

S>2All

S>Кстати, между прочим, в каких языках кроме .net-овских принято использовать стандартные интерфейсы контейнеров, аки IList<T>, чтобы можно было подсунуть разные реализации?

Дык как минимум в дотнет это попало из Явы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: А вы используете массивы?
От: Tilir Россия http://tilir.livejournal.com
Дата: 26.12.08 09:19
Оценка: 1 (1) :)
Здравствуйте, Mamut, Вы писали:

M>В чем фишка массивов? Хороший вопрос


Главная фишка массивов в том что они естественно отображаются на память компьютера. Любая другая структура данных искуственна и на уровне ассемблера затратна. Те же списки дико фрагментируют память и требуют дополнительного указателя на каждое хранимое значение. Поэтому там где нужно действительное быстродействие и рациональное использование памяти, там только фиксированные массивы в стиле C без альтернатив. Можно сразу закладываться и даже не гнать про premature optimization -- моя практика шагов вправо-влево показывает что по данным профилировки мне всё равно потом приходится на них заменять но уже резать по живому, и это гораздо сложнее. Вот если требования не так жёстки можно побаловаться удобства ради с другими структурами данных... Ну и редкие алгоритмические исключения. Когда хоть убей нужен логарифмический поиск и приходится делать дерево. Или критичны частые вставки внутрь за константное время и приходится делать список.
Re[7]: А вы используете массивы?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 26.12.08 09:37
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

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


S>>Если говорить о типе возвращаемого значения метода...

S>>Здесь будет одинаково уместно использовать T[] или List<T>, но List<T> удобнее, т.к. у него больше сервисов, потребитель метода сможет что-то с результатом сделать по своему усмотрению. Здесь главное не мешать массивы с листами, т.к. у одного Count а у другого Length

_FR>Не удобнее: Why we don’t recommend using List&lt;T&gt; in public APIs

_FR>От себя добавлю: если метод возвращает List<T>, то, учитывая, что этот класс никак не расширяем, реализация _вынуждена_ или возвращать уже имеющийся экземпляр List<T> или откуда-то копировать данные в List<T>.
Для паблик API — согласен. Между методами одного класса — для результата бывает использую List<T>.

Допустим, сегодня мой класс имеет поле типа List<T> и показывает его наружу через свойство типа List<T>. Но вот прошло время, и нам надо бы внутри класса реагировать на изменение списка. А как? List<T> подобной функциональности не предоставляет, и придётся менять интерфейс класса, тогда как при использовании интерфейсов подобное изменение можно было сделать "прозрачно" для внешнего мира. Или, например, потребовалось проверять, что в списке не более двух одинаковых значений. По-уму. надо написать своего наследника Collection<T>, в котором можно "прозрачно" для внешнего мира. Если мы не хотим менять интерфейс класса, нам придётся эту логику добавить в наш класс.
По уму не дело в качестве результата метода возвращать наследника Collection<T>. Такое обычно для свойств используется.

S>>Если говорить о типе возвращаемого значения свойства — то согласно тому же руководству принято считать, что при обращении к свойству вернется тот же самый экземпляр коллекции. И тогда надо думать о том, как бы этот экземпляр не испортить. T[] тут однозначно не подходит. List<T> может подойти если предусмотрено изменение коллекции, если не предусмотрено, то IList<T> и в качестве результата будет возвращаться readonly обертка.


_FR>А вот если мы знаем, что выставляем наружу "readonly обертку", то и тип надо использовать соответствующий: ReadOnlyCollection<>. Зачем List<>?

Про List<> для readonly я и не писал

S>>А IEnumerable возвращаю только там, где по каким-то причинам не удобно возвращать коллекцию, а выгодно вернуть именно перечислитель.


_FR>Через свойство? ИМХО, имеет право на жизнь, только если в классе есть поле типа IEnumerable. Тогда можно вернуть эту переменную. А вот такие свойства:

НЕНЕНЕ, IEnumerable через свойства не возвращаю. Просто описал после соображений для свойств, а получилось что отнес к свойствам...

S>>Кстати, считаю, что было бы здорово, если бы Enumerable.Range и подобные ему методы возвращали бы IList<int>. Ничего не стоило бы определить для того перечислителя Count и индексированный доступ к элементам.


_FR>Да ну: кому надо, ToList() или, что ещё лучше, ToArray() вызовет.

Довольно злая операция, если предположить что она вызывается в цикле... В то время как результат Range-а мог бы вести себя как список занимая лишь O(1) памяти. Остается надеяться на то, что кому надо не будут вызывать Range(i, i+1000000).ToArray()
Ладно, не об этом речь.

В общем, я считаю, что до появления Extension методов возвращать List<> для непубличных API могло бы быть оправдано набором функциональности List<>-а. И ToArray там, и ForEach, и FindAll... Но при вероятных изменениях типа результата это может привести к проблемам.
Re[2]: А вы используете массивы?
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 09:44
Оценка:
Здравствуйте, Tilir, Вы писали:
T>Главная фишка массивов в том что они естественно отображаются на память компьютера. Любая другая структура данных искуственна и на уровне ассемблера затратна. Те же списки дико фрагментируют память и требуют дополнительного указателя на каждое хранимое значение. Поэтому там где нужно действительное быстродействие и рациональное использование памяти, там только фиксированные массивы в стиле C без альтернатив.
Это сильно зависит от набора выполняемых операций. Подсказка: список — далеко не единственная альтернатива массиву.
И для многих сценариев (например, со вставками в середину) массивы в чистом виде непригодны. Также ограничением может служить доступный объем адресного пространства, так что для совсем-совсем больших структур массивы малопригодны.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: А вы используете массивы?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 26.12.08 10:00
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Все описанное является следствием используемой платформы и/или языка.


Да.
... << RSDN@Home 1.2.0 alpha 4 rev. 1132 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[10]: А вы используете массивы?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 26.12.08 10:51
Оценка:
Здравствуйте, Qbit86, Вы писали:

G>>Вообще с чего это в контракт входят временные асимптотики?


Q>Поэтому я и использую разные термины — интерфейс и контракт. Контракт, имхо, более широкое понятие, и включает в себя временные гарантии. IList<T> — интерфейс, LinkedList<T> — контракт. Это не преждевременная оптимизация, а избежание преждевременной пессимизации; я не считаю миллисекунды или такты, я учитываю асимптотику.

И что, асимптотику надо учитывать каждый раз, когда от параметра-коллекции требуется получить размер и обращаться по индексу?
В большенстве программ учитывать асимптотику надо в гораздо меньшем количестве мест, чем передавать IList.

Опять-таки требование параметром конкретного типа нарушает инкапсуляцию. Реализация метода может меняться, менять при этом контракт нежелательно.

G>>временные асимптотики — деталь реализации.

Q>Где-то тут близко — «Закон Дырявых Абстракций» Джоэля. Я не могу полностью абстрагироваться от реализации. Поэтому разработчики стандартной библиотеки и предоставили разные реализации для одних и тех же интерфейсов.
А кто мешает самому поступать также, принимать IList и использовать более подходящий алгоритм для разных типов?
Re[11]: А вы используете массивы?
От: Qbit86 Кипр
Дата: 26.12.08 11:17
Оценка:
G>Опять-таки требование параметром конкретного типа нарушает инкапсуляцию.

Это одно из проявлений Закона Дырявых Абстракций. Предположим, создатель библиотеки пишет функцию, которая принимает коллекцию, и в реализации часто-часто делает вставки в начало. У него есть два варианта: 1) Получить в аргументе LinkedList<T>; 2) Получать в аргументе IList<T> но писать в документации и в комментариях, что функция будет медленно работать на коллекциях, не поддерживающих быструю вставку. И в том, и в другом случае нарушается инкапсуляция. Но первый способ, имхо, честнее. Те же рассуждения остаются верными при замене (вставки-в-начало, LinkedList) ← (обращения-по-индексу, List).

Если считать временные гарантии частью контракта, то эта ситуация чем-то сродни отрицательной изменчивости (по Коплиену). Можно провести далёкую аналогию с некорректным наследованием квадрата от прямоугольника.

G>Реализация метода может меняться, менять при этом контракт нежелательно.


Если бы всё было так просто, то разработчики BCL не предоставляли бы разных коллекций, а только IList<T> и IDictionary<T>. В одной версии фреймворка их реализация по умолчанию использовала бы динамический массив и дерево. В следующей версии фреймворка разработчики именили бы реализацию на связный список и хэш-таблицу под предлогом «не надо закладываться на детали реализации». А у пользователей бы изменилась асимптотика их кода (причём не обязательно в худшую сторону).
Глаза у меня добрые, но рубашка — смирительная!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.