Здравствуйте, D. Mon, Вы писали:
EP>>В следующем году будут концепции — большой шаг вперёд. А что тут может предложить D? duck-typing?
DM>Я не знаю всех подробностей плюсовых концептов, но судя по тому, что Страуструп недавно рассказывал на Going Native, обещая в С++14, это уже очень давно есть в D в намного более удобном и мощном виде. Об этом же говорит Александреску.
Александреску скорей всего говорил о static if — что хоть и пересекается в некоторых простых use-case'а с концепциями, но всё таки является более примитивной feature. Пример использования концепций:
void sort(RandomAccessRange &x)
{
//...
}
void sort(BidirectionalRange &x)
{
//...
}
Это шаблоны функций, перегрузка между которыми происходит автоматом. Требования каждой концепции разбиваются компилятором на атомы, и производится тест вложенности множеств и т.п.
DM>Про производительность range'й не очень понял — где именно она хуже? В плюсах принято передавать два итератора, begin и end, в D их объединили в одну структуру, получили range.
DM>Смысл тот же, но меньше писанины и меньше ошибок.
Нет — range в D это другое — там совсем убрали итераторы, к ним вообще нет доступа.
Объедение итераторов в структуру это больше про
Boost.Range — что действительно сокращает "писанину" и позволяет избежать некоторые ошибки, но из таких Range можно получить доступ к итераторам — они их не прячут.
Итераторы C++ обеспечивают эффективную композицию. Если у нас есть 4 итератора, то из них можно получить 6 range бесплатно, без runtime penalty — просто выбери нужную пару итераторов.
Но, чисто range'ы без итераторов, как в D — теряют свойства композиции, код алгоритмов получается менее эффективным, что неприемлемо для C++. Например тот же
partition:
auto result = r;
for (;;)
{
for (;;)
{
if (r.empty) return result;
if (!pred(r.front)) break;
r.popFront();
result.popFront();
}
for (;;)
{
if (pred(r.back)) break;
r.popBack();
if (r.empty) return result;
}
swap(r.front, r.back);
r.popFront();
result.popFront();
r.popBack();
}
Чтобы вернуть вменяемый результат, параллельно "рабочему" range'у приходится передёргивать дополнительный range
result. В то время как в STL, нет этих лишних телодвижений — возвращается итератор, который практически бесплатно определяет два range'а.
Например код из SGI STL:
while (true)
{
while (true)
if (first == last) return first;
else if (pred(*first)) ++first;
else break;
--last;
while (true)
if (first == last) return first;
else if (!pred(*last)) --last;
else break;
iter_swap(first, last);
++first;
}