Здравствуйте, Erop, Вы писали:
E>Но я верно понял, что ты пришёл к убеждению, что интервалы вообще ненужное УГ, а итераторы, почти такое же УГ, просто чуть лучше и мягче?
Мой вердикт — для многих практических нужд дивных интервалов вполне хватает (подтверждено годом с лишним пракики), а для более заковыристых структур и алгоритмов актуальна прямая работа с этими структурами, тут посредники в виде итераторов и интервалов не так уж и нужны.
Здравствуйте, Erop, Вы писали:
E>Вообще-то, если у меня есть какая-то состоящая из как-то свзяанных между собой, содержащих данные узлов и нам надо перебрать все узлы, то у нас есть всего два варианта.
E>1) Написать код, который умеет выдавать нам узлы один за другим E>2) Написать код, который вызовет наш колбэк на каждом узле
E>(1) можно завернуть и в итераторы и в интервалы. В интервалы, как мы выше видели, выйдет хуже...
Ага, а вот как раз 2-ой вариант имеет прямую поддержку в D.
Нам достаточно переопределить у нашего типа Х операцию opApply (или opApplyReverse) и после этого мы сможем везде писать
foreach(х; Х){
...//тут любой код на D
}
Причём что самое главное, тут нигде нет никаких интервалов вообще. Т.е. для обычных случаев мы используем встроенные типы (массивы и словари), а для сложных случаев используем свои типы. И никаких range.
Единственная ситуация, в которой я сейчас их вспоминаю, это если вдруг очень захочется применить функции из std.algorithm к сущности не имеющей произвольного доступа к элементам (с RandomAccess сущностями функции из std.algorithm работают через срезы, а не через интервалы).
Здравствуйте, alex_public, Вы писали:
_>Причём что самое главное, тут нигде нет никаких интервалов вообще. Т.е. для обычных случаев мы используем встроенные типы (массивы и словари), а для сложных случаев используем свои типы. И никаких range.
Во-первых, в С++ точно так же.
Во-вторых, мы вроде как обсуждаем парадигмы, а не языки, в этой подветке.
но, главное, тут иное. Для foreach-то интервалы годятся, а вот для более сложных алгоритмов уже не особо...
_>Единственная ситуация, в которой я сейчас их вспоминаю, это если вдруг очень захочется применить функции из std.algorithm к сущности не имеющей произвольного доступа к элементам (с RandomAccess сущностями функции из std.algorithm работают через срезы, а не через интервалы).
Конечно же, через интервалы невозможно потому что, в силу обсуждаемой тут их убогости
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Во-первых, в С++ точно так же.
Не, в C++ не так совсем. Смотри ниже.
E>Во-вторых, мы вроде как обсуждаем парадигмы, а не языки, в этой подветке.
Да, но применимость этих парадигм в разных языках получается разная. Например лично я при работе на C++ использую STL постоянно, а при работе на D std.range считай что почти не использовал.
Вообще если проводить полное сравнение, то ситуация получается такая:
1. Массивы всяких разновидностей.
— В самом C++ есть кое-что встроенное, но крайне убогое. Все предпочитают использовать STL, которая в этом смысле довольно хороша.
— В D встроенные средства намного удобнее чем даже все возможности STL. Про Range при этом даже не вспоминаем.
2. Всяческие стандартные источники данных с не произвольным доступом (те же самые связные списки и т.п.).
— В самом C++ почти ничего нет, только поддержка циклов по итераторам (сущности из STL). А в STL великолепная реализация, как раз заточенная под такое.
— В самом D аналогично почти ничего нет, только поддержка циклов по диапазонам (сущности из библиотеки). В библиотеке D есть реализация через диапазоны, которая по возможностям хуже чем в STL.
3. Сложные пользовательские источники данных.
— В C++ есть минимальная поддержка через перегрузку операторов [] и *. Плюс есть возможность навесить на свой тип интерфейс контейнера STL, что даст нам возможность использовать циклы языка и алгоритмы из STL.
— В D есть гораздо большая поддержка из-за возможности перегрузки всех операторов, включая операторы среза, цикла, проверки наличия в словаре, доступа к члену (например можно реализовать контейнер Json, доступ к элементам которого будет в виде json.field) и т.п. Плюс есть возможность навесить на свой тип интерфейс диапазонов, что позволит нам использовать алгоритмы из std.algorithm (обычно нафиг не нужно для сложных типов).
В итоге, как мы видим по данному вопросу у этих двух языков в разных ситуациях есть свои плюсы и минусы. Но лично мне почему-то чаще встречаются на практике именно те ситуации (пункт 1 и 3), в которых сильнее D.
P.S. Основная деятельность у нас как раз на C++. )))
Здравствуйте, alex_public, Вы писали:
_>Да, но применимость этих парадигм в разных языках получается разная. Например лично я при работе на C++ использую STL постоянно, а при работе на D std.range считай что почти не использовал.
Что как бы намекает нам, что из двух удобнее/полезнее и т. д...
При этом С++ не содержит в самом языке никакой поддержки итераторов, вернее раньше не содержал, пока форич не привинтили, в отличии от ди...
_>В итоге, как мы видим по данному вопросу у этих двух языков в разных ситуациях есть свои плюсы и минусы. Но лично мне почему-то чаще встречаются на практике именно те ситуации (пункт 1 и 3), в которых сильнее D.
_>P.S. Основная деятельность у нас как раз на C++. )))
Ну у меня вот сложилось впечатдение, что диапазоны конкретно хуже, язык лучше, но лучше в основном в тех местах, который в большинстве моих задач не критичны...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, alex_public, Вы писали:
_>Нам достаточно переопределить у нашего типа Х операцию opApply (или opApplyReverse) и после этого мы сможем везде писать _>
_>foreach(х; Х){
_> ...//тут любой код на D
_>}
_>
_>Причём что самое главное, тут нигде нет никаких интервалов вообще.
Вот именно что нет — это просто передаётся continuation, со всеми вытекающими. В C++ для этого легко получить такой синтаксис:
FOREACH(x, X)
{
// ...
};
Но zip (одновременный обход двух контейнеров) на таком opApply уже не сделать.
Здравствуйте, D. Mon, Вы писали:
E>>Вот тебе пример алгоритма посложнее... DM>В алгоритмах посложнее итераторы все равно малополезны, там структуры данных и перемещение по ним редко сводится к хождению пешком туда-сюда (линейно) по одному элементу. То же дерево возьми, по нему итераторами будешь ходить?
Если по дереву нужно ходить именно как по дереву, то нужна соответствующая концепция. Например, тот же Степанов, в Elements of Programming показывает так называемые BifurcateCoordinate:
+ наборы соответствующих аксиом.
Для этих концепций реализуются соответствующие алгоритмы.
И эти координаты намного ближе к итераторам (которые, по-сути, являются координатами линейных структур), чем к Range.
Вот как сделать нечто подобное на тех принципах, которые используются в D Range?
Здравствуйте, Erop, Вы писали:
E>Ну у меня вот сложилось впечатдение, что диапазоны конкретно хуже, язык лучше, но лучше в основном в тех местах, который в большинстве моих задач не критичны...
Ну у нас аналогично. Собственно критичным (т.е. то что можно на D и нельзя на C++) могут быть только области как-то завязанные на метапрограммирование и т.п. Например как здесь http://vibed.org эти возможности использованы для создания шаблонизатора страниц времени компиляции. Кстати, мы как раз эту штуку используем в тестовом проектике...
А так в большинстве случае конечно D относительно C++ — это в основном масса мелких приятных вкусностей и всё. Ну хотя там ещё многопоточное программирование очень сильно представлено, но это в принципе всё и на C++ реализуется отдельными библиотеками.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Вот именно что нет — это просто передаётся continuation, со всеми вытекающими. В C++ для этого легко получить такой синтаксис: EP>
EP>FOREACH(x, X)
EP>{
EP> // ...
EP>};
EP>
Дааа? ) А как насчёт break и continue внутри такого кода на C++? )
Здравствуйте, alex_public, Вы писали:
EP>>Вот именно что нет — это просто передаётся continuation, со всеми вытекающими. В C++ для этого легко получить такой синтаксис: EP>>
EP>>FOREACH(x, X)
EP>>{
EP>> // ...
EP>>};
EP>>
_>Дааа? ) А как насчёт break и continue внутри такого кода на C++? )
При желании можно и break, и continue, и даже return получить (выше уже было), который кстати в D не работает
Самое простое это делать return BREAK; — точно также как делается в D, только с сахаром:
The body of the apply function iterates over the elements it aggregates, passing them each to the dg function. If the dg returns 0, then apply goes on to the next element. If the dg returns a nonzero value, apply must cease iterating and return that value. Otherwise, after done iterating across all the elements, apply will return 0.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>При желании можно и break, и continue,
Ну родные то не получится. ) Максимум макрос BREAK ввести (который внутри будет return 1 или что-то подобное и плюс ещё код анализирующий это), а это уже не то.
EP> и даже return получить (выше уже было), который кстати в D не работает
Эмм, в D return из кода в foreach (не важно по чему) как и положено вызовет выход из функции в которой расположен цикл, а не из этого куска кода. Кстати, ещё один пример того, что не будет работать на C++. Причём если попытаться и здесь макрос устроить, то всё будет намного сложнее, т.к. надо будет ещё как-то протаскивать через всю цепочку возвращаемое значение.
EP>Самое простое это делать return BREAK; — точно также как делается в D, только с сахаром:
Ну так собственно если не учитывать метапрограммирование, то D — это и есть сахар над C++. Только ведь сахар — это же тоже достаточно важно для эффективной работы. )
EP>То есть там return только целыми ограничен
Это вообще о другом. ))) Это речь про делегат, который генерирует компилятор из того куска кода и своих дополнений...
Здравствуйте, alex_public, Вы писали:
EP>>При желании можно и break, и continue, _>Ну родные то не получится. ) Максимум макрос BREAK ввести (который внутри будет return 1 или что-то подобное и плюс ещё код анализирующий это), а это уже не то.
Выше есть решение с родными break, continue и return.
EP>> и даже return получить (выше уже было), который кстати в D не работает _>Эмм, в D return из кода в foreach (не важно по чему) как и положено вызовет выход из функции в которой расположен цикл, а не из этого куска кода.
Точно? Попробуй вернуть объект какого-нибудь произвольно типа, а не int.
Здравствуйте, alex_public, Вы писали:
EP>>Выше есть решение с родными break, continue и return. _>Эээ что за решение? )
Кодт показывал код. Где-то в первой половине сообщений.
EP>>Точно? Попробуй вернуть объект какого-нибудь произвольно типа, а не int.
_>Такой код _>выводит _>
_>1
_>2
_>[5, 6]
_>
А как именно оно внутри работает? Какой путь проделывает объект от return'а?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Если по дереву нужно ходить именно как по дереву, то нужна соответствующая концепция.
Именно!
EP>И эти координаты намного ближе к итераторам (которые, по-сути, являются координатами линейных структур), чем к Range. EP>Вот как сделать нечто подобное на тех принципах, которые используются в D Range?
По-моему, этот вопрос не имеет смысла.
Итератор — воплощение идеи координаты, прокачанный указатель, он имеет какой-то смысл в контексте дерева.
Range — воплощение идеи последовательности, для нелинейных структур смысла не имеет (за исключением перечисления элементов, но это операция вырожденная).
Здравствуйте, D. Mon, Вы писали:
EP>>И эти координаты намного ближе к итераторам (которые, по-сути, являются координатами линейных структур), чем к Range. EP>>Вот как сделать нечто подобное на тех принципах, которые используются в D Range? DM>По-моему, этот вопрос не имеет смысла. DM>Итератор — воплощение идеи координаты, прокачанный указатель, он имеет какой-то смысл в контексте дерева. DM>Range — воплощение идеи последовательности, для нелинейных структур смысла не имеет (за исключением перечисления элементов, но это операция вырожденная).
Надо шире смотреть: range — воплощение идеи работы со структурой, и её подмножествами.
BifurcateRange ещё можно придумать — отрезаем либо левую часть, либо правую, вместе с головой — прямая аналогия popFront из ForwardRange.
А вот с аналогом BidirectionalBifurcateCoordinate — опять начинаются те же проблемы, что и с BidirectionalRange.
Здравствуйте, D. Mon, Вы писали:
EP>>Если по дереву нужно ходить именно как по дереву, то нужна соответствующая концепция. DM>Именно!
А разве итераторы обязуются решать все задачи?
Ну там кофе они не умеют варить. Хотя кто его знает что там в кофемашинах используется, возможно даже и STL с итераторами
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Кодт показывал код. Где-то в первой половине сообщений.
О, я это как-то пропустил всё. А оказывается прямо тоже самое уже обсуждали. )))
Ну да, в общем то решение как у Кодта я себе и представлял. Правда до идеи дополнительной функции и цикла для отлова нативных не успел дойти.
EP>А как именно оно внутри работает? Какой путь проделывает объект от return'а?
Без понятия, но для компилятора то так протащить точно не проблема.
Почитал топик. Здешний основной спор вокруг STL-итераторов и D-диапазонов заставил перечитать статью Александреску On Iteration. В принципе, вроде как, он вполне адекватно описывает причины выбора ranges, их плюсы и кривости тоже.
Заодно глянул в потроха итераторов у D-конкурентов — у Rust-строителей. Собственно, даже для стандартного вектора итератор не есть тонкая обвёртка над простым указателем. И похоже, что в стандартной библиотеке особо не рассчитывают хранить итераторы в коллекциях, а также и указатели на хранимые в контейнерах значения, особенно с учётом того, что, как правило, контейнеры блокируются для модификаций на время жизни созданного итератора или ссылки на хранимое значение.
А вообще-то, на сегодня уже хотелось бы обходиться без объектных итераторов и прочих энумераторов, например, по мотивам reducers кложуры.
Здравствуйте, PSV100, Вы писали:
PSV>В принципе, вроде как, он вполне адекватно описывает причины выбора ranges, их плюсы и кривости тоже.
Дык о том и речь же, что D более компромиссный, чем С++, в результате получилось уже не С++, но ещё не C#
То есть, если ты выбираешь из D и C++, и склоняешься с D, то не ясно, почему не к C#?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском