Здравствуйте, D. Mon, Вы писали:
EP>>Причём проверки такого вида были доступны и в C++11, через decltype, только в более нагромождённой форме. DM>В С++ это только обещают, в D это давно есть.
Проверки с таким синтаксисом уже есть через decltype.
DM>Но не только это, а выполнение почти произвольного кода. Прочитать файл, отсортировать, распарсить, посчитать...
Это действительно круто(так же круто как и mixins), но эта фича слабо связанна с концепциям
DM>Проверить компилируемость выражения, опять же, и в зависимости от результата делать осмысленные вещи.
В каком виде? В смысле только SFINAE-like или, допустим, можно поймать static_assert где-то в глубине call-stack'а?
EP>> Вообще "проверка выполнения аксиом" — звучит крайне дико DM>Если тебе нужно реализовать, например, класс кольца или группы, то в тестах нужно проверить, что выполнены аксиомы кольца/группы. Это просто математика. Не нравится такое слово, можно говорить о "законах", каковое слово и было в посте.
1. Перегружаться на основе таких тестов крайне опасно: практически никогда нельзя проверить все возможные значения — на тестовых оно пройдёт, а на других сфейлится заодно поломав инварианты.
2. С другой стороны, сам пользователь может знать, что на некоторых значениях эти свойства не выполняются, и не использует эти значения в runtime — а в такой проверке как раз будет это значение.
3. Даже если есть набор правильных тестовых значений, не всегда есть возможность протестировать все свойства. Вот например, есть такой алгоритм std::find, одним из его постусловий является то, что в range [first, result_of_find) нет искомого значения. В случае single pass range нет никакой возможности проверить это постусловие через black-box test.
4. Какой тест позволит различить InputIterator и ForwardIterator?
5. Пользователь может сознательно "расслабить семантику типа". Например он может специально "наделить" сложение floating-point чисел ассоциативностью, которой у них нет, чтобы сделать parallel reduction.
В общем "проверка аксиом" крайне сомнительная затея
Здравствуйте, Кодт, Вы писали:
К>>>Не путай свои требования и главные требования. M>>Где они спутаны? Цитату в студию или трепло. К>У тебя в голове спутаны.
Отличный аргумент! Т.е. ты себе придумал, что ты один разбираешься в мэйнстриме и мне на словах вменяешь, будто это я ошибаюсь. Где логика, сэр? Ты уж если хочешь спорить, опирайся хотя бы на цитаты — без них твоё словоблудие ровно ничего не доказывает и только провоцирует конфликты.
К>Задумайся на досуге о том, что промышленность так и не выкинула си. Неспроста, наверное.
На, тоже задумайся:
Если бы Си был действительно подходящим языком, он бы не плёлся десятилетиями как говно на палочке 17%, а вытеснил бы всякую шушеру и был бы "языком №1" с 80% рынка. А используется он исключительно в двух случаях: 1) экстремальные запросы к производительности 2) куча легаси кода, включая какие-нибудь библиотечки "вывода в ком-порт", которые тащат из проекта в проект и для упрощения всё остальное тоже пишут на Сях.
С этими фактами ты спорить не будешь?
По всем остальным аспектам Си — г-но мамонта, безумно затягивающее разработку и до сих пор (напоминаю, 21 век!) подкладывает свинью в виде stack overflow, null pointer, range overwrite и.т.п. — ТАКОМУ в мэйнстриме не место. И если ты посмотришь на C#, то он практически "взлетел" — и это на фоне твоего "мэйнстримного Си" и Жабы — заметь, тоже вроде как претендовавшего на "безопасный Си".
Т.е. если уж кто и претендует сейчас на мэйнстрим, но это, пожалуй, единственный язык — C#. У Ди финансы уровня плинтуса, поэтому увы, он не может проталкивать себя так же активно.
Да, и С++ — тоже обрати внимание на график, он "скатился" практически до уровня Objective-C — языка для нишевой макоси. Почему-то Аппля не стала ставить даже на С++ (хотя подумай, сколько уже написанных библиотек они могли бы поиметь нахаляву!).
M>>...Ди предлагает куда более интересные вещи (CTFE, mixins, ranges, RTTI), под которые надо ЗАНОВО писать код. К>Вот-вот, надо заново писать код. Кто будет платить кодерам?
Те же, кто платили за Сипиписных монстров! Что в этом такого? Новый софт делался и будет делаться, весь вопрос лишь в том, хватит ли ума "боссам" не создавать очередной "быстробегущий труп", чтобы потом годами латать дыры и молиться, чтобы все оба "специалиста по указателям" не махнули из конторы. И в то же время есть громадный выбор C# спецов, знания которых на порядок ценнее, потому что это не знания о костылях языка, а высокоуровневая CS.
К>Народ вовсю фортраном пользуется, чтобы адский матан не переписывать на модные академические языки.
Фортран, Ада — это всё тоже прекрасный пример отстоя, который держат исключительно за "пока ещё работает" и "дорого/незачем переписывать". Ну и сам посуди как руководитель: нужно начинать проект и выбирать язык. Ты что, будешь опираться на древние пылесосы с фортраном, потому что там есть оптимизированый косинус и потом ещё два года искать пердунов, ещё помнящих отступ в 6 пробелов?!! Легаси — оно и есть легаси, подумай насколько высоко прыгнула парадигма от жонглирования указателей в перделках на 1000 строк к облачным вычислениям, паттернам, модульным системам, ООП и прочее — да это небо и земля! Сейчас на "сишной логике" можно писать разве что команду dir — средние и выше системы она уже не потянет.
Здравствуйте, FR, Вы писали:
EP>>Такой foreach есть в C++98: boost::fusion::for_each. Не хватает только полиморфной лямбды (нужно вручную делать function object), которую скоро добавят. FR>Ну реально же страшно по сравнению с D.
Имхо, ничего страшного
FR>И не дай бог мелкую ошибку допустить и получим километровое сообщение,
Против километровых ошибок помогут концепции.
FR>и чуть начни более менее интенсивно такое применять, даже на мелких проектах будет компиляция несколько минут минимум.
В таком самодельном полиморфном for_each нет ничего, что принципиально будет сильно тормозить компиляцию.
FR>В D же все прозрачно, просто, одинаково что в компил что в ран тайм и без "синтаксического оверхеда"
FR>>>Ну и плюс такой сахар как Template Constraints позволяет писать в стиле контрактов нового С++, хотя конечно с более примитивным матчингом. EP>>Это же и есть один из вариантов static if, аналог которого есть в C++98 — enable_if. FR>Это да, я и писал про сахар, но это только одно мелкое применение, ну и опять удобней и проще.
Это не удобней, не проще и не наглядней чем концепции:
Здравствуйте, FR, Вы писали:
EP>>В C++ добавят range'ы (которые пара итераторов) — afaik для этого есть целая study group. FR>Уже в 14 ?
Вряд ли, скорее в C++17. Но range не к спеху, так как есть Boost.Range.
FR>>>Ну и кстати написать для D итераторы ничего не мешает, и эффективность у них будет такой же как и в C++, так что FR>>>к недостаткам языка их отсутствие никак нельзя отнести. EP>>Во-первых что-то для range'ей уже встроено непосредственно в язык, тот же foreach или slice'ы. FR>Нет для foreach range не нужны http://dlang.org/statement.html#ForeachStatement достаточно перезагрузки FR>операторов: [...]. Для slice аналогично.
Для стандартных массивов перегрузки в библиотеке или в языке?
EP>>Пара лишних инкремнтов будут на простейших range'ах, а если там что-то более сложное? FR>А что может быть еще сложнее?
Сам range может быть чем угодно — например может управлять файловой системой. Где-то передёргивание будет незаметным (а где-то может быть убрано компилятором), но не во всех range'ах это простейшие операции.
FR>Что-то функций с десятком итераторов я не видел.
В смысле?
FR>И опять таки скажем даже тот же std::transform (первое что пришло в голову с кучей итераторов) переведется на range без всякой потери производительности.
std::transform это простейший случай. Но даже в нём проявляется неудобство.
У него результат итератор — я могу спокойно соединить этот итератор с теми, что у меня были ранее (или с теми, что получу потом), образуя новые range'ы бесплатно.
FR>В результате как я и говорил все сведется к достаточно узким случаям. EP>>Мой поинт в том, что если абстракция порождает не-эффективный код by-design — то это изначально плохая абстракция. FR>Зависит от ситуации.
Я показал конкретную ситуацию в стандартной библиотеке D и сравнил её side-by-side с STL.
Здравствуйте, D. Mon, Вы писали:
DM>Про производительность range'й не очень понял — где именно она хуже? В плюсах принято передавать два итератора, begin и end, в D их объединили в одну структуру, получили range. Смысл тот же, но меньше писанины и меньше ошибок.
Ну бывают же не только пары итераторов, но и тройки, скажем, или, наоборот, одинокие итераторы, например итератор элемента std::list'а...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, matumba, Вы писали:
M>Надеюсь, что уже сам пример использования таким "гигантом", станет хорошим вдохновителем для масс — многие просто боятся использовать что-то малораздутое или новоиспечённые выскочки типа Rust/Go. Ди развивается уже много лет и к счастью — без давления легаси или коммерческой продавабельности (как C#), так что если под Ди встанет хороший фундамент инвестиций, сипипи-убожества навсегда покинут индустрию.
В целом я с вами согласен, С++ рано или поздно должен уступить место лучшим языкам (D вполне подходит), но выражаетесь вы весьма экстравагантно.
Здравствуйте, matumba, Вы писали:
M>С чего вы решили, что вообще нужно переносить этот хлам??? Ди — не просто повторение "Си с классами", а практически новая методология! Ну или сильно улучшенная, как нравится. Т.е. переносить старые костыли нет никакого смысла, Ди предлагает куда более интересные вещи (CTFE, mixins, ranges, RTTI),
Ну ценность большинства кода состоит не в его технической части, а в содержательной...
M>под которые надо ЗАНОВО писать код.
Вот это-то и печалит...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Ну бывают же не только пары итераторов, но и тройки, скажем, или, наоборот, одинокие итераторы, например итератор элемента std::list'а...
Кстати, по поводу списков — тут дело не только в производительности.
На основе ForwardIterator'ов можно определить LinkedIterator (добавив функцию set_successor) — который позволяет изменять next. На основе таких итераторов можно реализовать разные алгоритмы, типа reverse, merge sort, etc:
template <typename I> // I models Linked Iterator
I reverse_append(I first, I limit, I result)
{
while (first != limit) {
I old_successor = successor(first);
set_successor(first, result);
result = first;
first = old_successor;
}
return result;
}
Но я, например, сходу не вижу как легко можно расширить D Range для поддержки чего-то похожего.
То есть я думаю что концепция "координаты", которая лежит в основе STL итераторов — более фундаментальна для алгоритмов и структур данных, чем Ranges.
Или взять, например, концепцию BifurcateCoordinate из "Elements of Programming"
Здравствуйте, Erop, Вы писали:
E>Ну бывают же не только пары итераторов, но и тройки, скажем, или, наоборот, одинокие итераторы, например итератор элемента std::list'а...
Ну так и в D range это не обязательно пара. Для списка он будет как плюсовый. Range — это нечто (обычно структура, но необязательно) с определенным интерфейсом. Что внутри — уже детали реализации.
Здравствуйте, FR, Вы писали:
E>>Ну бывают же не только пары итераторов, но и тройки, скажем, или, наоборот, одинокие итераторы, например итератор элемента std::list'а... FR>D'шный range не пара итераторов.
Вообще-то как раз про одинокие итераторы jazzer выше приводил ссылку на комментарий A.A.:
Another example of an iterator-based design that's not easy to replicate with ranges is Boost Multi-Index. (Thanks Emil Dotchevski for pointing that out during my talk. (Marshall Clow promised the video will be available Real Real Soon Now(tm).)) In Multi-Index, indexes store iterators; storing ranges would often waste twice the space for little
or no benefit.
А про тройки итераторов — посмотри например на std::partition, возвращая один итератор он даёт нам два новых range'а, причём мы их получаем бесплатно (путём комбинации с имеющимся итераторами).
Или например std::nth_element/partial_sort которые принимают три итератора из одного range
FR>Это весьма абстрактная вещь, минимально и достаточно для (односвязного) списка это: FR>
По факту D Range нормально подходит только для SinglePass.
С Birirectional — проблемы с производительностью, на практических алгоритмах вылезают лишние передёргивания. В RandomAccess используются обычные целочисленные индексы, которые даже менее безопасны чем итераторы.
С Forward тоже ничего хорошего. Например std::find возвращает итератор, который бесплатно определяет два Range — до и после. А вот что советует сделать A.A. чтобы получить первый range:
Another weakness I noticed is visible when translating STL algorithms that return one iterator, such as find, which has this signature:
It find(It b, It e, E value)
where It is a one-pass iterator type and E is the type referenced by the iterator. STL's find returns the first iterator iter between b and (excluding) e that satisfies *iter == value. Once that iterator is returned, you can combine it with b to obtain the range before value, or with e to obtain the range after value.
Ranges lack such capabilities. The range-based find has this signature:
Range find(Range r, E value)
It consumes from r until it finds value and returns what's left of r. This means that you get access to the portion after the found value, but not before.
Fortunately, this problem is easily solved by defining a new range type, Until. Until is a range that takes another range r and a value v, starts at the beginning of r, and ends just before r.front() == v (or at the natural end of r if v is not to be found). Lazy computation for the win!
Причём std::find это один из самых примитивных алгоритмов
Изобрази пожалуйста самый примитивный пример: функция печатающая названия типов своих
аргументов, только законченный компилируемый пример, на D это будет так:
import std.stdio;
void print_type(A...)(A a)
{
foreach(T; A)
writeln(typeid(T));
}
void main()
{
print_type(1, 2.0, "3");
}
EP>+ если не нравится boost::mpl::vector, то легко сделать for_each который будет принимать сразу variadic pack.
Это уже гораздо лучше, но шума, опять же по моему, гораздо больше необходимого, особенно
если учесть что никаких метабиблиотек мой пример не использовал.
Здравствуйте, FR, Вы писали:
FR>Да спасибо, для меня вполне демонстрирует что С++11 с D по выразительности шаблонов состязаться не может.
void print_type(A...)(A a)
{
foreach(T; A)
writeln(typeid(T));
}
// versustemplate<typename ...Ts> void foo(Ts...)
{
for_each<Ts...>([](auto x)
{
writeln(type_name(decltype(x)));
});
}
Это называется чуть больше сахара.
FR>Это уже гораздо лучше, но шума, опять же по моему, гораздо больше необходимого, особенно FR>если учесть что никаких метабиблиотек мой пример не использовал.
Так наоборот хорошо что многое реализуемо в библиотеке. Я, например, предпочёл бы какой-нибудь дополнительный синтаксис для лямбд, вместо range-based-for.
EP>Для стандартных массивов перегрузки в библиотеке или в языке?
В языке.
EP>Сам range может быть чем угодно — например может управлять файловой системой. Где-то передёргивание будет незаметным (а где-то может быть убрано компилятором), но не во всех range'ах это простейшие операции.
Согласен, но в таких случаях часто ленивость спасает.
FR>>Что-то функций с десятком итераторов я не видел.
EP>В смысле?
В прямом
Итераторов мало обычно.
EP>std::transform это простейший случай. Но даже в нём проявляется неудобство. EP>У него результат итератор — я могу спокойно соединить этот итератор с теми, что у меня были ранее (или с теми, что получу потом), образуя новые range'ы бесплатно.
По моему у тебя идея фикс "новые range бесплатно" , по моему гораздо чаще нужны цепочки обрабатывающие range.
EP>Я показал конкретную ситуацию в стандартной библиотеке D и сравнил её side-by-side с STL.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Это называется чуть больше сахара.
Да и прямое следствие из него шаблонный код на D легко читается в отличии от аналога на C++.
EP>Так наоборот хорошо что многое реализуемо в библиотеке. Я, например, предпочёл бы какой-нибудь дополнительный синтаксис для лямбд, вместо range-based-for.
Одно другому не мешает, нужен и сахар в языке и мощные мета возможности для построения библиотек.
По моему для C++ идея что надо стараться максимально возможно реализовывать все в библиотеках плохо
подходит (при всем уважении к Страуструпу) для этого мета возможности C++ совершенно недостаточны.
Здравствуйте, FR, Вы писали:
EP>>Для стандартных массивов перегрузки в библиотеке или в языке? FR>В языке.
О чём и речь — что-то для range'ей уже встроено непосредственно в язык.
EP>>Сам range может быть чем угодно — например может управлять файловой системой. Где-то передёргивание будет незаметным (а где-то может быть убрано компилятором), но не во всех range'ах это простейшие операции. FR>Согласен, но в таких случаях часто ленивость спасает.
У нас чистый permutation алгоритм — std::partition. В Phobos'е лишний раз дёргаются ручки у range'а, как тут поможет ленивость?
EP>>std::transform это простейший случай. Но даже в нём проявляется неудобство. EP>>У него результат итератор — я могу спокойно соединить этот итератор с теми, что у меня были ранее (или с теми, что получу потом), образуя новые range'ы бесплатно. FR>По моему у тебя идея фикс "новые range бесплатно" ,
Не только у меня — смотри выше что пишет A.A. про std::find — чтобы получить первую часть, нужно делать реализовывать новый тип range — Until, в то время как в STL он действительно получается бесплатно: [first, find(first, last, x))
FR>по моему гораздо чаще нужны цепочки обрабатывающие range.
Здравствуйте, FR, Вы писали:
EP>>Это называется чуть больше сахара. FR>Да и прямое следствие из него шаблонный код на D легко читается в отличии от аналога на C++.
Это скорей всего так и есть, но отнюдь никак не следует из сравнения этих кусочков в 7 строк.
FR>По моему для C++ идея что надо стараться максимально возможно реализовывать все в библиотеках плохо FR>подходит (при всем уважении к Страуструпу) для этого мета возможности C++ совершенно недостаточны.
И meta-возможности у C++ постепенно расширяются, есть study group для reflection. Конечно не так быстро как в языке у которого целых полтора компилятора