Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
вы имеете ввиду динамический полиморфизм? легко можно, но получим тогда что-то такое тормозное, типа явы.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Можно. А нужно?
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Теперь осталось разобраться , почему же было сделано именно так а не иначе.
Здравствуйте, Sni4ok, Вы писали:
S>Здравствуйте, DelphiGuru, Вы писали:
DG>>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
S>вы имеете ввиду динамический полиморфизм? легко можно, но получим тогда что-то такое тормозное, типа явы.
Я имею в виду, то что его можно реализавать именно в том виде, в каком он есть в Си++, то есть алгоритмы будут независимы от контейнеров, более того, я считаю, что контейнеры не более чем примерами использования алгоритмов, т.к. на тех же плюсах я могу использовать алгоритмы STL и на велосипедных контейнерах.
Здравствуйте, Sni4ok, Вы писали:
S>Здравствуйте, DelphiGuru, Вы писали:
DG>>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
S>вы имеете ввиду динамический полиморфизм? легко можно, но получим тогда что-то такое тормозное, типа явы.
Ну ява не настолько тормозная, как вы думаете. При должном умении она уже давно на уровне С++ в задачах типа конвертации больших объемов информации/ роутинга сообщений и т.п.
Здравствуйте, 0x7be, Вы писали:
0>Здравствуйте, DelphiGuru, Вы писали:
DG>>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом 0>Можно. А нужно?
Здравствуйте, blackhearted, Вы писали:
B>Ну ява не настолько тормозная, как вы думаете. При должном умении она уже давно на уровне С++ в задачах типа конвертации больших объемов информации/ роутинга сообщений и т.п.
всё верно, в тех задачах где хорош перл или питон- ява тоже на уровне.
Здравствуйте, blackhearted, Вы писали:
B>Ну ява не настолько тормозная, как вы думаете. При должном умении она уже давно на уровне С++ в задачах типа конвертации больших объемов информации/ роутинга сообщений и т.п.
Большие XML-файлы в стек-трейсы?
Здравствуйте, 0x7be, Вы писали:
0>Здравствуйте, blackhearted, Вы писали:
B>>Ну ява не настолько тормозная, как вы думаете. При должном умении она уже давно на уровне С++ в задачах типа конвертации больших объемов информации/ роутинга сообщений и т.п. 0>Большие XML-файлы в стек-трейсы?
Сарказм понятен
Здравствуйте, Sni4ok, Вы писали:
S>Здравствуйте, blackhearted, Вы писали:
B>>Ну ява не настолько тормозная, как вы думаете. При должном умении она уже давно на уровне С++ в задачах типа конвертации больших объемов информации/ роутинга сообщений и т.п.
S>всё верно, в тех задачах где хорош перл или питон- ява тоже на уровне.
Здравствуйте, DelphiGuru, Вы писали:
DG>Я имею в виду, то что его можно реализавать именно в том виде, в каком он есть в Си++, то есть алгоритмы будут независимы от контейнеров, более того, я считаю, что контейнеры не более чем примерами использования алгоритмов, т.к. на тех же плюсах я могу использовать алгоритмы STL и на велосипедных контейнерах.
Реализуйте хотя бы прототип, концепт. Думаю что сообщество C++ поставит вам памятник при жизни.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Лет десять назад у меня тоже была такая мысль.
Но лень победила.
Я просто сделал себе аналог вектора на... макросах.
С тех пор так и живу.
И не нужен мне STL (ну кроме работы) уж десять лет как.
Эээ... "Тот самый" STL вроде написали два человека.
Так что задача вполне подьемная. Дерзай.
Здравствуйте, DelphiGuru, Вы писали:
DG>Я имею в виду, то что его можно реализавать именно в том виде, в каком он есть в Си++, то есть алгоритмы будут независимы от контейнеров, более того, я считаю, что контейнеры не более чем примерами использования алгоритмов, т.к. на тех же плюсах я могу использовать алгоритмы STL и на велосипедных контейнерах.
Это весьма очевидная вещь. Вопрос в другом — какие преимущества и недостатки будет иметь чисто ООП версия?
И, кстати, такой вопрос — ООП версия подразумевает использование шаблонов/дженериков?
Здравствуйте, blackhearted, Вы писали:
B>каких-таких расчётах? B>например в HFT ява уже близка к С++.
само HFT нагруженной системой не является, вон победитель последнего конкурса- тык на питоне написан, другое дело бектестинг- там где плюсы переберут 100к параметров, ява только 50к, при том что самого по себе кода внутри стратегии немного- и лишние издержки на железо в данном месте хоть и не принципиальны, но они не необходимы.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Си++ — это источник бабала, возможность найти себе работу практически в любой стране, да Дельфи нет. Что там внутри технологии мне поровну.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Уточните пожалуйста, в каком месте вашей задумки закончатся шаблоны и начнётся ООП. Не понятно.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Что значит чистое ООП ? STL вдруг перестала быть ООП ?
Пока что никто не смог доказать, что лямбда-счисление Черча превосходит по мощности машину тьюринга, что означает что любую задачу можно ка попало решить.
Здравствуйте, shrecher, Вы писали:
S>Здравствуйте, DelphiGuru, Вы писали:
DG>>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
S>Си++ — это источник бабала, возможность найти себе работу практически в любой стране, да Дельфи нет. Что там внутри технологии мне поровну.
Отвечаю всем.
1- Шаблонов и дженериков не будет
2- Лень побеждает в 4 раз за 2 года
3- При появлении везде дженериков не вижу смысла выкладывать. На Дельфи уже вовсю смарт пойнтеры кропают
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, DelphiGuru, Вы писали:
DG>>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
I>Что значит чистое ООП ? STL вдруг перестала быть ООП ?
I>Пока что никто не смог доказать, что лямбда-счисление Черча превосходит по мощности машину тьюринга, что означает что любую задачу можно ка попало решить.
1-STL сроду не ООП. Там в половине случаев вообще можно обойтись без шаблонов, при использовании столь мощной абстракции как итераторы.
2-Вектор реализован вообще через одно место. Чтобы мне пройти вектор по не последовательно, а используя другой способ формирования следующей позиции — то облом.
про map уже гдето здесь писали, что способ представления жестко зашит и его не поменяешь
Здравствуйте, DelphiGuru, Вы писали:
DG>2-Вектор реализован вообще через одно место. Чтобы мне пройти вектор по не последовательно, а используя другой способ формирования следующей позиции — то облом.
Вектор прекрасно индексируется. Если надо на итераторах, то std::advance к итератору вектора имеет сложность операции сложения.
DG>про map уже гдето здесь писали, что способ представления жестко зашит и его не поменяешь
конкретику в студию. Что именно нужно получить, но нельзя из-за "жёсткого представления"
Здравствуйте, DelphiGuru, Вы писали:
S>>вы имеете ввиду динамический полиморфизм? легко можно, но получим тогда что-то такое тормозное, типа явы. DG>Я имею в виду, то что его можно реализавать именно в том виде, в каком он есть в Си++, то есть алгоритмы будут независимы от контейнеров, более того, я считаю, что контейнеры не более чем примерами использования алгоритмов, т.к. на тех же плюсах я могу использовать алгоритмы STL и на велосипедных контейнерах.
Т.е. речь идёт о том, чтобы для совместимости с интерфейсом оставить шаблоны где нужно, а внутри ввести операции боксинга-анбоксинга? А в чём-смысл?
Здравствуйте, DelphiGuru, Вы писали:
I>>Пока что никто не смог доказать, что лямбда-счисление Черча превосходит по мощности машину тьюринга, что означает что любую задачу можно ка попало решить. DG>1-STL сроду не ООП. Там в половине случаев вообще можно обойтись без шаблонов, при использовании столь мощной абстракции как итераторы.
Шаблоны это не ооп ?
DG>2-Вектор реализован вообще через одно место. Чтобы мне пройти вектор по не последовательно, а используя другой способ формирования следующей позиции — то облом.
Возможности обхода это ООП ?
DG>про map уже гдето здесь писали, что способ представления жестко зашит и его не поменяешь
Т.е. если способ представления поменять нельзя, стало быть это не ООП ?
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, DelphiGuru, Вы писали:
I>>>Пока что никто не смог доказать, что лямбда-счисление Черча превосходит по мощности машину тьюринга, что означает что любую задачу можно ка попало решить. DG>>1-STL сроду не ООП. Там в половине случаев вообще можно обойтись без шаблонов, при использовании столь мощной абстракции как итераторы.
I>Шаблоны это не ооп ?
DG>>2-Вектор реализован вообще через одно место. Чтобы мне пройти вектор по не последовательно, а используя другой способ формирования следующей позиции — то облом.
I>Возможности обхода это ООП ?
DG>>про map уже гдето здесь писали, что способ представления жестко зашит и его не поменяешь
I>Т.е. если способ представления поменять нельзя, стало быть это не ООП ?
Я что, должен копипастить весь шаблон vector, чтобы иметь возможность иногда менять строго поэлементный просмотр на нечто другое. А если бы методы возвращающие итераторы были виртуальными все было бы гораздо проще:
class MyVector: public Vector<MyType>{
virtual ittype begin{}
и т. д (прошу прошения за ошибки, давно не писал)
}
А про количичество типов деревьев, которые наиболее производительно каждое на своем сегменте задач я вообще не говорю. а В STL зашит один тип и его не поменяешь
Здравствуйте, DelphiGuru, Вы писали:
I>>Т.е. если способ представления поменять нельзя, стало быть это не ООП ? DG>Я что, должен копипастить весь шаблон vector, чтобы иметь возможность иногда менять строго поэлементный просмотр на нечто другое.
ООП и хороший/плохой дизайн это вещи никак между собой не связаные.
И то и другое может быть как в ООП так и безо всякого ООП.
Чего ты хотел сказать про STL, что тебе не нравятся возможности, что тебе не нравится дизайн, что ты не считаешь это ООП ?
Здравствуйте, DelphiGuru, Вы писали:
DG>Я что, должен копипастить весь шаблон vector, чтобы иметь возможность иногда менять строго поэлементный просмотр на нечто другое. А если бы методы возвращающие итераторы были виртуальными все было бы гораздо проще: DG>class MyVector: public Vector<MyType>{ DG> virtual ittype begin{} DG> и т. д (прошу прошения за ошибки, давно не писал) DG>} DG>А про количичество типов деревьев, которые наиболее производительно каждое на своем сегменте задач я вообще не говорю. а В STL зашит один тип и его не поменяешь
Погоди, а что не давало перегузить метод?
Если ты делаешь свой тип, наследный от vector, перекрываешь невиртуальный метод и потом указываешь его в параметрах шаблонов функций, то будет вызван твой метод, а не метод vector.
Здравствуйте, Sni4ok, Вы писали:
S>в расчётах, где-же ещё.
C++ именно в расчетах, в которых критична скорость, совершенно не оправдан. Потому что как только речь заходит об оптимизации по скорости все высокоуровневые абстракции C++ применять нельзя. От C++ остается фактически только Си, который и используется в расчетах. Да и Фортран в вычислениях до сих пор широко используется и не только для поддержки старого кода. Еще один минус C++ в этом случае — это Name mangling из-за чего усложняется использование C++-ных библиотек в других средах и даже просто других компиляторов.
Так что писать сугубо вычислительную часть на C++ неразумно.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Пишу на C++. Писал на Delphi. STL использую. ООП использую. Вопроса не понял.
Здравствуйте, DelphiGuru, Вы писали:
DG>Здравствуйте, Ikemefula, Вы писали:
I>>Здравствуйте, DelphiGuru, Вы писали:
DG>>>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
I>>Что значит чистое ООП ? STL вдруг перестала быть ООП ?
I>>Пока что никто не смог доказать, что лямбда-счисление Черча превосходит по мощности машину тьюринга, что означает что любую задачу можно ка попало решить. DG>1-STL сроду не ООП. Там в половине случаев вообще можно обойтись без шаблонов,
Какое отношение это имеет к ООП? Никакого. Это имеет отношение к дизайну.
DG>при использовании столь мощной абстракции как итераторы. DG>2-Вектор реализован вообще через одно место. Чтобы мне пройти вектор по не последовательно, а используя другой способ формирования следующей позиции — то облом.
Какое отношение это имеет к ООП? Никакого. Это имеет отношение к дизайну.
DG>про map уже гдето здесь писали, что способ представления жестко зашит и его не поменяешь
Какое отношение это имеет к ООП? Никакого. Это имеет отношение к дизайну.
Странно, ты считашь, что в стл не чистый ООП, а примеры приводишь не по ООП, а по дизайну библиотеки
I>>Возможности обхода это ООП ?
DG>>>про map уже гдето здесь писали, что способ представления жестко зашит и его не поменяешь
I>>Т.е. если способ представления поменять нельзя, стало быть это не ООП ? DG>Я что, должен копипастить весь шаблон vector, чтобы иметь возможность иногда менять строго поэлементный просмотр на нечто другое. А если бы методы возвращающие итераторы были виртуальными все было бы гораздо проще: DG>class MyVector: public Vector<MyType>{ DG> virtual ittype begin{} DG> и т. д (прошу прошения за ошибки, давно не писал) DG>} DG>А про количичество типов деревьев, которые наиболее производительно каждое на своем сегменте задач я вообще не говорю. а В STL зашит один тип и его не поменяешь
Какое отношение это имеет к ООП? Никакого. Это имеет отношение к дизайну. Менее ООП оно от этого не становится
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
ты потратил неделю своей жизни в пустую, вот что мы думаем
Здравствуйте, lazy_walrus, Вы писали:
_>Здравствуйте, Константин Л., Вы писали:
КЛ>>ты потратил неделю своей жизни в пустую, вот что мы думаем
_>Мы, царь всея Руси?
ну я. какая разница. предвосхищая вопросы — если чел пялился в исходники неделю и в 2011 задает такие вопросы и делает такие предположения, значит он зря потратил своё время
Здравствуйте, Michael7, Вы писали:
M>Здравствуйте, Sni4ok, Вы писали:
S>>в расчётах, где-же ещё.
M>C++ именно в расчетах, в которых критична скорость, совершенно не оправдан. Потому что как только речь заходит об оптимизации по скорости все высокоуровневые абстракции C++ применять нельзя.
+1. Своими глазами видел в коде GCC
if (current_abstraction_level > 4)
enable_optimization = 0;
M>Еще один минус C++ в этом случае — это Name mangling из-за чего усложняется использование C++-ных библиотек в других средах и даже просто других компиляторов. M>Так что писать сугубо вычислительную часть на C++ неразумно.
Здравствуйте, Константин Л., Вы писали:
КЛ>ну я. какая разница. предвосхищая вопросы — если чел пялился в исходники неделю и в 2011 задает такие вопросы и делает такие предположения, значит он зря потратил своё время
А почему зря? Человек с опытом программирования на Delphi изучил исходники STL, расширил свой кругозор, у него возникли понятные вопросы почему STL сделан так а не иначе, и нельзя ли сделать лучше.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Я тоже так думаю. Только уточни, что именно ты имеешь в виду.
Там где нужны большие скорости вычислений, реально C++ лажает или кто-то станет туда пихать шаблоны, перегрузки операторов, множественное наследование, с запутанными иногда вызовами виртуальных функций и т.п. чтобы потом задолбаться, профилируя узкие места?
Тогда уж для математики лучше вместо C++ использовать Ada.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Можно ли в Армении построить коммунизм? Можно, но лучше в Грузии
а чистый ООП пусть живет где-нибудь в дельфях, нам в c++ такого счастья не надо
Здравствуйте, Michael7, Вы писали:
M>Да и Фортран в вычислениях до сих пор широко используется и не только для поддержки старого кода. Еще один минус C++ в этом случае — это Name mangling из-за чего усложняется использование C++-ных библиотек в других средах и даже просто других компиляторов.
офигеть. а типа в фортране этого нет?
M>Так что писать сугубо вычислительную часть на C++ неразумно.
Здравствуйте, Michael7, Вы писали:
M>Здравствуйте, Sni4ok, Вы писали:
S>>в расчётах, где-же ещё.
M>C++ именно в расчетах, в которых критична скорость, совершенно не оправдан. Потому что как только речь заходит об оптимизации по скорости все высокоуровневые абстракции C++ применять нельзя.
А пацаны то и не знали сделали ublas с нативными байндами.
M> От C++ остается фактически только Си, который и используется в расчетах. Да и Фортран в вычислениях до сих пор широко используется и не только для поддержки старого кода. Еще один минус C++ в этом случае — это Name mangling из-за чего усложняется использование C++-ных библиотек в других средах и даже просто других компиляторов.
M>Так что писать сугубо вычислительную часть на C++ неразумно.
Здравствуйте, nullptr, Вы писали:
n> Можно ли в Армении построить коммунизм? Можно, но лучше в Грузии n> а чистый ООП пусть живет где-нибудь в дельфях, нам в c++ такого счастья не надо
Не наезжай на дельфю, нету там чистого ООП и небыло никогда
Здравствуйте, minorlogic, Вы писали:
M>>C++ именно в расчетах, в которых критична скорость, совершенно не оправдан. Потому что как только речь заходит об оптимизации по скорости все высокоуровневые абстракции C++ применять нельзя. M>А пацаны то и не знали сделали ublas с нативными байндами.
Ublas — медленная библиотека. А вот быстрая оптимизированная Sun Performance Library, тоже реализующая функционал BLAS, таки на фортране сделана. Как и Lapack, например.
M>>Так что писать сугубо вычислительную часть на C++ неразумно.
M>GIL, VIGRA, BGL на другие мысли не наводят ?
Не имел с ними дела, но беглый гуглеж показывает, что это отнюдь не эталон быстродействия.
Здравствуйте, Andrey.V.Lobanov, Вы писали:
M>>...Еще один минус C++ в этом случае — это Name mangling из-за чего усложняется использование C++-ных библиотек в других средах и даже просто других компиляторов. AVL>офигеть. а типа в фортране этого нет?
А что, в Фортране есть name mangling? А когда оно там появилось? В те времена, когда у меня в проекте исполняемый файл собирался из идущих вперемешку С- и фортрановских исходников, я ничего подобного не замечал.
M>>Так что писать сугубо вычислительную часть на C++ неразумно. AVL>
Может, и неразумно, но по той причине, что числодробилки на С читаются труднее, чем на Фортране. IMHO, разумеется.
Здравствуйте, Privalov, Вы писали:
M>>>...Еще один минус C++ в этом случае — это Name mangling из-за чего усложняется использование C++-ных библиотек в других средах и даже просто других компиляторов. AVL>>офигеть. а типа в фортране этого нет? P>А что, в Фортране есть name mangling? А когда оно там появилось? В те времена, когда у меня в проекте исполняемый файл собирался из идущих вперемешку С- и фортрановских исходников, я ничего подобного не замечал.
ну, lower/upper case и всякие подчёркивания (по разному в разных компиляторах — за подробностями хоть в вики) вполне за mangling пойдут
M>>>Так что писать сугубо вычислительную часть на C++ неразумно. AVL>> P>Может, и неразумно, но по той причине, что числодробилки на С читаются труднее, чем на Фортране. IMHO, разумеется.
в плане читаемости да, согласен. только я и не предполагал, что мы тут за читаемость говорим...
Здравствуйте, Michael7, Вы писали:
M>Здравствуйте, minorlogic, Вы писали:
M>>>C++ именно в расчетах, в которых критична скорость, совершенно не оправдан. Потому что как только речь заходит об оптимизации по скорости все высокоуровневые абстракции C++ применять нельзя. M>>А пацаны то и не знали сделали ublas с нативными байндами.
M>Ublas — медленная библиотека. А вот быстрая оптимизированная Sun Performance Library, тоже реализующая функционал BLAS, таки на фортране сделана. Как и Lapack, например.
Я бы не назвал медленной, хотя и не близко к лидерам. Просто есть много моментов которые на голом C повторить довольно непросто. А для скорострельности Ublas предоставляет байнды к нихкоуровневым реализациям.
M>>>Так что писать сугубо вычислительную часть на C++ неразумно.
M>>GIL, VIGRA, BGL на другие мысли не наводят ?
M>Не имел с ними дела, но беглый гуглеж показывает, что это отнюдь не эталон быстродействия.
Здравствуйте, lazy_walrus, Вы писали:
_>Здравствуйте, Константин Л., Вы писали:
КЛ>>ну я. какая разница. предвосхищая вопросы — если чел пялился в исходники неделю и в 2011 задает такие вопросы и делает такие предположения, значит он зря потратил своё время
_>А почему зря? Человек с опытом программирования на Delphi изучил исходники STL, расширил свой кругозор, у него возникли понятные вопросы почему STL сделан так а не иначе, и нельзя ли сделать лучше.
подожди, ты всерьез считаешь, что после недельного изучения stl нормальный человек будет утверждать что (курсив мой, ибо а как иначе?)
ее можно реализовать при помощи чистого ООП не потеряв ничего в фичах и гибкости
?
Я считаю, что чел смотрел неделю и ничего в итоге не понял
Здравствуйте, Michael7, Вы писали:
M>>>C++ именно в расчетах, в которых критична скорость, совершенно не оправдан. Потому что как только речь заходит об оптимизации по скорости все высокоуровневые абстракции C++ применять нельзя. M>>А пацаны то и не знали сделали ublas с нативными байндами.
M>Ublas — медленная библиотека. А вот быстрая оптимизированная Sun Performance Library, тоже реализующая функционал BLAS, таки на фортране сделана. Как и Lapack, например.
SPL смотрится круто, но для таких библиотек характерна одна проблема: они требуют определённого расположения данных в памяти. Если весь расчёт можно сделать в рамках одной библиотеки, то это не проблема вообще, но если для других операция требуется иное расположение данных то потребуется их конвертация и копирование. В C++ же, благодаря шаблонам, возможно реализовать обобщённые алгоритмы, которые могут работать с различными структурами данных без полиморфизма времени исполнения. А механизм специализации шаблонов позволяет по итогам профилирования оптимизировать код с минимальными изменениями программы в целом.
1) Архитектура STL — это ФП переложенное на императив с помощью шаблонов.
2) Итераторы при всей похожести на указатели являются на самом деле замыканиями в чистом виде, используя терминологию ФП.
3) Из 2 следует, что итераторы, в принципе, можно определять и вне контейнера. Все, что нужно для создания итератора — это контейнер и тип хранимого в данном контейнере. И следовательно, итератор, указывающий на конец, в принципе не нужен, если мы все равно проверяем, то проверять надо в итераторе, указывающем начало.
Здравствуйте, DelphiGuru, Вы писали:
DG>3) Из 2 следует, что итераторы, в принципе, можно определять и вне контейнера. Все, что нужно для создания итератора — это контейнер и тип хранимого в данном контейнере. И следовательно, итератор, указывающий на конец, в принципе не нужен, если мы все равно проверяем, то проверять надо в итераторе, указывающем начало.
Здравствуйте, DelphiGuru, Вы писали:
DG>2) Итераторы при всей похожести на указатели являются на самом деле замыканиями в чистом виде, используя терминологию ФП.
Итераторы являются замыканиями? Что то не уловил глубину мысли. Ты closures с continuations, случаем, не попутал?
Здравствуйте, Michael7, Вы писали:
M>Здравствуйте, minorlogic, Вы писали:
M>>>C++ именно в расчетах, в которых критична скорость, совершенно не оправдан. Потому что как только речь заходит об оптимизации по скорости все высокоуровневые абстракции C++ применять нельзя. M>>А пацаны то и не знали сделали ublas с нативными байндами.
M>Ublas — медленная библиотека. А вот быстрая оптимизированная Sun Performance Library, тоже реализующая функционал BLAS, таки на фортране сделана. Как и Lapack, например.
Чет путаете, вроде Sun Performance Library использует не фортрановские имплементации.
Насколько я помню, есть библиотеки заточенные на нативный перфоманс. Кажется eigen называется.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Итераторы являются замыканиями? Что то не уловил глубину мысли. Ты closures с continuations, случаем, не попутал?
Ну замыкание в реализации итератора явно присутствует, во первых итератор держит в себе ссылку на контейнер во вторых позицию
в контейнере, вот простейшая реализация на OCaml
let get_iter l =
let lref = ref l in
let next () =
match !lref with
| [] -> None
| a::b -> (lref := b; Some a)
in next
let rec print it =
match it () with
| Some x -> (Printf.printf "%d\n" x; print it)
| None -> ()
;;
print (get_iter [1; 2; 3; 4])
Здравствуйте, Константин Л., Вы писали:
КЛ>Здравствуйте, lazy_walrus, Вы писали:
_>>Здравствуйте, Константин Л., Вы писали:
КЛ>>>ну я. какая разница. предвосхищая вопросы — если чел пялился в исходники неделю и в 2011 задает такие вопросы и делает такие предположения, значит он зря потратил своё время
_>>А почему зря? Человек с опытом программирования на Delphi изучил исходники STL, расширил свой кругозор, у него возникли понятные вопросы почему STL сделан так а не иначе, и нельзя ли сделать лучше.
КЛ>подожди, ты всерьез считаешь, что после недельного изучения stl нормальный человек будет утверждать что (курсив мой, ибо а как иначе?)
КЛ>
КЛ>ее можно реализовать при помощи чистого ООП не потеряв ничего в фичах и гибкости
КЛ>Я считаю, что чел смотрел неделю и ничего в итоге не понял
Если человек всю жизнь писал на Дельфях — это естественно, не?
Я имею в виду его вопрос, а не то, что ничего не понял.
Здравствуйте, Ikemefula, Вы писали:
I>>>Шаблоны это не ооп ?
FR>>Нет конечно концепция ортогональная ООП.
I>А по подробнее ?
Они реализуют совершенно другую концепцию — обобщенное программирование которое никакого отношения к ООП не имеет и может реализовыватся как в ООП языках например C++ или D так и в процедурных например в Ada так и в функциональных например Hope.
Другая сторона шаблонов — метапрограммирование также ортогональна ООП.
"The Scheme work led to a grant to produce a generic library in Ada"
Начинали на схеме, потом была Ада, потом С++ А если я кое что похожее начинал на асме, не зная ничего про ФП, стало быть функции цельнотянутые из императивного ассемблера ?
Здравствуйте, FR, Вы писали:
FR>Они реализуют совершенно другую концепцию — обобщенное программирование которое никакого отношения к ООП не имеет и может реализовыватся как в ООП языках например C++ или D так и в процедурных например в Ada так и в функциональных например Hope.
"обобщенное программирование" это всего лишь полиморфизм, который, к слову, в с++ оформлен достаточно жиденько.
Здравствуйте, Ikemefula, Вы писали:
I>"The Scheme work led to a grant to produce a generic library in Ada"
I>Начинали на схеме, потом была Ада, потом С++ А если я кое что похожее начинал на асме, не зная ничего про ФП, стало быть функции цельнотянутые из императивного ассемблера ?
А читать с начала не пробовал?
In the late 70’s I became aware of John Backus’s work on FP1. While his idea of programming with functional forms struck me as essential, I realized that his attempt to permanently fix the number of functional forms was fundamentally wrong. The number of functional forms – or as I call them now – generic algorithms is always growing as we discover new algorithms. In 1980 together with Dave Musser and Deepak Kapur I started working on a language Tecton to describe algorithms defined on algebraic theories. The language was functional since I did not realize at the time that memory and pointers were a fundamental part of programming. I also spent time studying Aristotle and his successors and that lead me to a better understanding of fundamental operations on objects like equality and copying and the relation between whole and part.
Тут он прямо пишет что все цельнотянуто из FP но ему был нужен более низкий уровень, что он успешно и осуществил реализовав STL.
FR>In the late 70’s I became aware of John Backus’s work on FP1. While his idea of programming with functional forms struck me as essential, I realized that his attempt to permanently fix the number of functional forms was fundamentally wrong. The number of functional forms – or as I call them now – generic algorithms is always growing as we discover new algorithms. In 1980 together with Dave Musser and Deepak Kapur I started working on a language Tecton to describe algorithms defined on algebraic theories. The language was functional since I did not realize at the time that memory and pointers were a fundamental part of programming. I also spent time studying Aristotle and his successors and that lead me to a better understanding of fundamental operations on objects like equality and copying and the relation between whole and part.
FR>Тут он прямо пишет что все цельнотянуто из FP но ему был нужен более низкий уровень, что он успешно и осуществил реализовав STL.
С таким подходом вообще все получается цельнотянутым из ФП
Здравствуйте, FR, Вы писали:
I>>"обобщенное программирование" это всего лишь полиморфизм, который, к слову, в с++ оформлен достаточно жиденько.
FR>Чуть больше http://en.wikipedia.org/wiki/Generic_programming
Чем это отличается от параметрического полиморфизма ?
Здравствуйте, Ikemefula, Вы писали:
FR>>Тут он прямо пишет что все цельнотянуто из FP но ему был нужен более низкий уровень, что он успешно и осуществил реализовав STL.
I>С таким подходом вообще все получается цельнотянутым из ФП
Нет не получается, автор тут сам прямо говорит откуда взял.
Здравствуйте, FR, Вы писали:
I>>Чем это отличается от параметрического полиморфизма ?
FR>Тем что параметрический полиморфизм это один из способов обобщенного программирования.
По твоей же ссылке, кстати говоря, "Generic programming is a style of computer programming in which algorithms are written in terms of to-be-specified-later types that are then instantiated when needed for specific types provided as parameters. This approach, pioneered by Ada in 1983, permits writing common functions or types that differ only in the set of types on which they operate when used, thus reducing duplication"
"Ada is a structured, statically typed, imperative, wide-spectrum, and object-oriented high-level computer programming language, extended from Pascal and other languages. "
Ты точно это хотел сказать ?
Если STL это обобщенное, то растет это из Ада, что следует из твоей ссылки т.е. императивщина. Ну а схемы здесь просто как вариант реализации.
Здравствуйте, Ikemefula, Вы писали:
I>По твоей же ссылке, кстати говоря, "Generic programming is a style of computer programming in which algorithms are written in terms of to-be-specified-later types that are then instantiated when needed for specific types provided as parameters. This approach, pioneered by Ada in 1983, permits writing common functions or types that differ only in the set of types on which they operate when used, thus reducing duplication"
I>"Ada is a structured, statically typed, imperative, wide-spectrum, and object-oriented high-level computer programming language, extended from Pascal and other languages. "
I>Ты точно это хотел сказать ?
I>Если STL это обобщенное, то растет это из Ада, что следует из твоей ссылки т.е. императивщина. Ну а схемы здесь просто как вариант реализации.
Оно растет не только из Ады там же и ML указан и не указаны те же Hope или CLU (когда еще Ады и в проекте не было там уже были параметризованные типы). Ада просто первый достаточно массовый язык с обобщенным программированием.
Обобщенное программирование ортогонально императивщине и функциональщине.
Здравствуйте, FR, Вы писали:
I>>Если STL это обобщенное, то растет это из Ада, что следует из твоей ссылки т.е. императивщина. Ну а схемы здесь просто как вариант реализации.
FR>Оно растет не только из Ады там же и ML указан и не указаны те же Hope или CLU (когда еще Ады и в проекте не было там уже были параметризованные типы). Ада просто первый достаточно массовый язык с обобщенным программированием. FR>Обобщенное программирование ортогонально императивщине и функциональщине.
Итого — STL это обобобщенное программирование, которое реализовано в ОО-языке с помощью ОО-инструмента — шаблонов
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, FR, Вы писали:
I>>>Если STL это обобщенное, то растет это из Ада, что следует из твоей ссылки т.е. императивщина. Ну а схемы здесь просто как вариант реализации.
FR>>Оно растет не только из Ады там же и ML указан и не указаны те же Hope или CLU (когда еще Ады и в проекте не было там уже были параметризованные типы). Ада просто первый достаточно массовый язык с обобщенным программированием. FR>>Обобщенное программирование ортогонально императивщине и функциональщине.
I>Итого — STL это обобобщенное программирование, которое реализовано в ОО-языке с помощью ОО-инструмента — шаблонов
Шаблоны не являются ОО-инструментом ну вообще никак. Их можно отнести к МП.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
G>>Шаблоны не являются ОО-инструментом ну вообще никак. Их можно отнести к МП.
I>Ну да, полиморфизм к ООП никакого отношения не имеет
ООП обычно использует довольно слабый вид полиморфизма: ad-hoc полиморфизм по неявному аргументу.
Шаблоны и генерики не относятся к ООП вообще никак.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Ikemefula, Вы писали:
I>>Здравствуйте, gandjustas, Вы писали:
G>>>Шаблоны не являются ОО-инструментом ну вообще никак. Их можно отнести к МП.
I>>Ну да, полиморфизм к ООП никакого отношения не имеет
G>ООП обычно использует довольно слабый вид полиморфизма: ad-hoc полиморфизм по неявному аргументу.
G>Шаблоны и генерики не относятся к ООП вообще никак.
Здравствуйте, Константин Л., Вы писали:
КЛ>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, Ikemefula, Вы писали:
I>>>Здравствуйте, gandjustas, Вы писали:
G>>>>Шаблоны не являются ОО-инструментом ну вообще никак. Их можно отнести к МП.
I>>>Ну да, полиморфизм к ООП никакого отношения не имеет
G>>ООП обычно использует довольно слабый вид полиморфизма: ad-hoc полиморфизм по неявному аргументу.
КЛ>G>Шаблоны и генерики не относятся к ООП вообще никак.
КЛ>однако они дают статический полиморфизм
И что? Причем тут ООП?
[]
G>>>ООП обычно использует довольно слабый вид полиморфизма: ad-hoc полиморфизм по неявному аргументу.
КЛ>>G>Шаблоны и генерики не относятся к ООП вообще никак.
КЛ>>однако они дают статический полиморфизм
G>И что? Причем тут ООП?
Здравствуйте, Michael7, Вы писали:
M>C++ именно в расчетах, в которых критична скорость, совершенно не оправдан.
Он оправдан там, где _сложность_
Что касается скорости, то не забываем, что критичного кода к остальному даже не 20:80, а где-то от 5:95 до 1:99 при внимательном изучении
Также не забываем, что с современными оптимизаторами практически нет смысла соревноваться на низком уровне
Гораздо более важно иметь _гибкость_ — возможность легко заменять реализацию какого-либо алгоритма, подзадачи.
Здравствуйте, Head Ache, Вы писали:
HA>Здравствуйте, Michael7, Вы писали:
M>>C++ именно в расчетах, в которых критична скорость, совершенно не оправдан.
HA>Он оправдан там, где _сложность_ HA>Что касается скорости, то не забываем, что критичного кода к остальному даже не 20:80, а где-то от 5:95 до 1:99 при внимательном изучении HA>Также не забываем, что с современными оптимизаторами практически нет смысла соревноваться на низком уровне HA>Гораздо более важно иметь _гибкость_ — возможность легко заменять реализацию какого-либо алгоритма, подзадачи.
Если бы всё было так, то ради гибкости код бы писался на питоне, а оставшийся 1% — на Си или Фортране. =)))
я вот до того как померил думал что сишного кода
в меркуриале не 5% а как минимум 20%.
Понятно что полно приложений которые так не напишешь, но такие гибриды вполне конкуренты C++ и даже яве с шарпом.
Здравствуйте, Head Ache, Вы писали:
HA>Здравствуйте, Michael7, Вы писали:
M>>C++ именно в расчетах, в которых критична скорость, совершенно не оправдан.
HA>Он оправдан там, где _сложность_
И чем он оправдан там где сложность?
Скорее наоборот. Сложность реализации простых вещей оправдывается языком C++, но при этом во всю говорят о том как это эффективно.
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, Mazay, Вы писали:
M>>Если бы всё было так, то ради гибкости код бы писался на питоне, а оставшийся 1% — на Си или Фортране. =)))
FR>Тык и пишут http://www.rsdn.ru/forum/design/4127605.1.aspx
я вот до того как померил думал что сишного кода FR>в меркуриале не 5% а как минимум 20%. FR>Понятно что полно приложений которые так не напишешь, но такие гибриды вполне конкуренты C++ и даже яве с шарпом.
Да-да. Я там как-то криво написал. Короче не важно сколько там процентов критичного по производительности кода. Важно что если такого кода много (1% от дофига, это всё равно дофига) и он сложный, то его удобно писать на C++. То есть С++ это удачный компромисс между производительностью и современными языковыми средствами. Почти нулевой пенальти и почти все современные тулзы. Страдает при этом понятность языка для человека. Классический случай "Овцы целы, волки сыты. Так погиб чабан Никита".
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Собственно говоря, отличие в том, что на С++ это делать не нужно. А преимущество это или недостаток...
Здравствуйте, Mazay, Вы писали:
M>Здравствуйте, FR, Вы писали:
FR>>Здравствуйте, Mazay, Вы писали:
M>>>Если бы всё было так, то ради гибкости код бы писался на питоне, а оставшийся 1% — на Си или Фортране. =)))
FR>>Тык и пишут http://www.rsdn.ru/forum/design/4127605.1.aspx
я вот до того как померил думал что сишного кода FR>>в меркуриале не 5% а как минимум 20%. FR>>Понятно что полно приложений которые так не напишешь, но такие гибриды вполне конкуренты C++ и даже яве с шарпом.
Здравствуйте, shrecher, Вы писали:
S>Здравствуйте, DelphiGuru, Вы писали:
DG>>На Дельфи уже вовсю смарт пойнтеры кропают
S>Главное, что дельфа никому не надо. В лучшем случае поддержка старья.
Здравствуйте, DelphiGuru, Вы писали:
DG>Здравствуйте, Ikemefula, Вы писали:
I>>Здравствуйте, DelphiGuru, Вы писали:
DG>>>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
I>>Что значит чистое ООП ? STL вдруг перестала быть ООП ?
I>>Пока что никто не смог доказать, что лямбда-счисление Черча превосходит по мощности машину тьюринга, что означает что любую задачу можно ка попало решить. DG>1-STL сроду не ООП. Там в половине случаев вообще можно обойтись без шаблонов, при использовании столь мощной абстракции как итераторы. DG>2-Вектор реализован вообще через одно место. Чтобы мне пройти вектор по не последовательно, а используя другой способ формирования следующей позиции — то облом. DG>про map уже гдето здесь писали, что способ представления жестко зашит и его не поменяешь
Я смотрю, набросы про STL дают много корма нашим зелёным друзьям...
Здравствуйте, Anton Batenev, Вы писали:
AB>Здравствуйте, blackhearted, Вы писали:
b>> я не в курсе. b>> Он их on server-side считает?
AB>Для mercurial термин server-side не совсем корректен. Хотя, смотря что считать сервером.
Где он диффы считает? На локальной машине в локальном репозитории?
Здравствуйте, FR, Вы писали:
FR>Ну замыкание в реализации итератора явно присутствует, во первых итератор держит в себе ссылку на контейнер во вторых позицию FR>в контейнере
Но это же не означает эквивалентности. Замыкание — особенность реализации итератора, а не основная его функция.
Здравствуйте, blackhearted, Вы писали:
AB>>Для mercurial термин server-side не совсем корректен. Хотя, смотря что считать сервером.
B>Где он диффы считает? На локальной машине в локальном репозитории?
Здравствуйте, blackhearted, Вы писали:
b> AB>Для mercurial термин server-side не совсем корректен. Хотя, смотря что считать сервером. b> Где он диффы считает? На локальной машине в локальном репозитории?
Типа того. Моя ремарка была к тому, что у меркуриала нет сервера — каждый клон репозитория самодостаточен (а уж способ работы — локально или SSH, хранилище — локально или SSHFS, вещи достаточно вариабельные). Ремарка не имеет отношения к спору C++ vs Delphi.
Здравствуйте, gandjustas, Вы писали:
I>>Ну да, полиморфизм к ООП никакого отношения не имеет
G>ООП обычно использует довольно слабый вид полиморфизма: ad-hoc полиморфизм по неявному аргументу.
Обычно, но это не значит что это единсвенно возможный вариант
G>Шаблоны и генерики не относятся к ООП вообще никак.
Это всего лишь реализация тех возможностей, которые динамически типизируемые ОО-языки умеют "искаропки"
Здравствуйте, Anton Batenev, Вы писали:
AB>Здравствуйте, blackhearted, Вы писали:
b>> AB>Для mercurial термин server-side не совсем корректен. Хотя, смотря что считать сервером. b>> Где он диффы считает? На локальной машине в локальном репозитории?
AB>Типа того. Моя ремарка была к тому, что у меркуриала нет сервера — каждый клон репозитория самодостаточен (а уж способ работы — локально или SSH, хранилище — локально или SSHFS, вещи достаточно вариабельные). Ремарка не имеет отношения к спору C++ vs Delphi.
ИМХО, он не сильно сложные там расчёты... подветка таки про производительность и применимость сипласплас.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>Ну да, полиморфизм к ООП никакого отношения не имеет
G>>ООП обычно использует довольно слабый вид полиморфизма: ad-hoc полиморфизм по неявному аргументу.
I>Обычно, но это не значит что это единсвенно возможный вариант
Для самого ООП — единственно возможный. Остальные способы полиморфизма не имеют отношения к ООП никак.
G>>Шаблоны и генерики не относятся к ООП вообще никак. I>Это всего лишь реализация тех возможностей, которые динамически типизируемые ОО-языки умеют "искаропки"
Вот только динамическая типизация не делает программы надежнее, а нам надо повышать уровень абстракции без снижения надежности кода.
Здравствуйте, gandjustas, Вы писали:
I>>Обычно, но это не значит что это единсвенно возможный вариант G>Для самого ООП — единственно возможный. Остальные способы полиморфизма не имеют отношения к ООП никак.
Открой принципы Алана Кея, там полиморфизма столько надо, сколько во всем с++ не накопаешь
G>>>Шаблоны и генерики не относятся к ООП вообще никак. I>>Это всего лишь реализация тех возможностей, которые динамически типизируемые ОО-языки умеют "искаропки" G>Вот только динамическая типизация не делает программы надежнее, а нам надо повышать уровень абстракции без снижения надежности кода.
Статическая типизация тоже не делает программы надежнее. Приходится писать в разы больше кода, приседать вокруг депенденсов, выдумывать всякие конструкции, и в итоге код имеет ровно те же проблемы.
Даже "укушеные Александреску" и те внагрузку к с++ используют какую динамику по мелочи.
А вообще ты в курсе, какие проекты пишутся на js, питоне, эрланге ?
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>Обычно, но это не значит что это единсвенно возможный вариант G>>Для самого ООП — единственно возможный. Остальные способы полиморфизма не имеют отношения к ООП никак. I>Открой принципы Алана Кея, там полиморфизма столько надо, сколько во всем с++ не накопаешь
G>>>>Шаблоны и генерики не относятся к ООП вообще никак. I>>>Это всего лишь реализация тех возможностей, которые динамически типизируемые ОО-языки умеют "искаропки" G>>Вот только динамическая типизация не делает программы надежнее, а нам надо повышать уровень абстракции без снижения надежности кода.
I>Статическая типизация тоже не делает программы надежнее.
Да ну?
I>Приходится писать в разы больше кода, приседать вокруг депенденсов, выдумывать всякие конструкции, и в итоге код имеет ровно те же проблемы.
Докажешь?
Если уж на то пошло, то большая часть того что пишется в динамике может быть выражена и в статике. Ну конечно зависит от языка.
Но вот самое интересное получается когда надо править код.
Например есть цепочка вызовов A=>B=>C=>...=>Y=>Z и внезапно в Z сменился тип параметра. В статике перестанет компилироваться, ты поправишь, потребуется поменять параметры Y, и так далее. В итоге скомпилируется у тебя программа только если ты поправишь все несоответствия.
Если есть вывод типов, то картина еще радужнее. Типы сами автоматически выведутся кроме тех мест, где возникнут конфликты. В итоге тебе надо будет править только те места, где изменится семантика.
А в случае динамического языка у тебя будет в рантайме выпадать ошибка. Причем выпадать она может не всегда.
Чтобы получить надежность кода на уровне статического варианта тебе нужно написать для этого дела тест.
То есть для любой цепочки вызовов в динамическом языке нужен тест чтобы программа была не менее надежная, чем в варианте со статической типизацией.
Здравствуйте, gandjustas, Вы писали:
G>>>>>Шаблоны и генерики не относятся к ООП вообще никак. I>>>>Это всего лишь реализация тех возможностей, которые динамически типизируемые ОО-языки умеют "искаропки" G>>>Вот только динамическая типизация не делает программы надежнее, а нам надо повышать уровень абстракции без снижения надежности кода.
I>>Статическая типизация тоже не делает программы надежнее. G>Да ну?
Ну да.
I>>Приходится писать в разы больше кода, приседать вокруг депенденсов, выдумывать всякие конструкции, и в итоге код имеет ровно те же проблемы. G>Докажешь?
Запрограммируй на С#/С++ конечный автомат какой. Сравни с его реализацией скажем на Питоне или Руби. Сделай выводы.
G>Если уж на то пошло, то большая часть того что пишется в динамике может быть выражена и в статике. Ну конечно зависит от языка.
Может и что ?
G>А в случае динамического языка у тебя будет в рантайме выпадать ошибка. Причем выпадать она может не всегда.
G>Чтобы получить надежность кода на уровне статического варианта тебе нужно написать для этого дела тест.
Зато в с#, C++ придется городить всякие визиторы
G>То есть для любой цепочки вызовов в динамическом языке нужен тест чтобы программа была не менее надежная, чем в варианте со статической типизацией.
В итоге и там и там придется тесты писать, а основная логика в динамическом языке будет гораздо проще читаться.
Здравствуйте, Ikemefula, Вы писали:
I>Запрограммируй на С#/С++ конечный автомат какой. Сравни с его реализацией скажем на Питоне или Руби. Сделай выводы.
Давай, показывай код на питоне, сравним с тем, как это в nemerle будет выглядеть.
I>Зато в с#, C++ придется городить всякие визиторы
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
G>>>>>>Шаблоны и генерики не относятся к ООП вообще никак. I>>>>>Это всего лишь реализация тех возможностей, которые динамически типизируемые ОО-языки умеют "искаропки" G>>>>Вот только динамическая типизация не делает программы надежнее, а нам надо повышать уровень абстракции без снижения надежности кода.
I>>>Статическая типизация тоже не делает программы надежнее. G>>Да ну?
I>Ну да.
I>>>Приходится писать в разы больше кода, приседать вокруг депенденсов, выдумывать всякие конструкции, и в итоге код имеет ровно те же проблемы. G>>Докажешь?
I>Запрограммируй на С#/С++ конечный автомат какой. Сравни с его реализацией скажем на Питоне или Руби. Сделай выводы.
А в чем проблема на C# сделать функцию из IEnumerable<T> в IEnumerable<V> на yield return?
На C++ все плохо.
Только причем тут динамика?
G>>Если уж на то пошло, то большая часть того что пишется в динамике может быть выражена и в статике. Ну конечно зависит от языка. I>Может и что ?
То что утверждение про "писать в разы больше кода" несостоятельно.
G>>А в случае динамического языка у тебя будет в рантайме выпадать ошибка. Причем выпадать она может не всегда. G>>Чтобы получить надежность кода на уровне статического варианта тебе нужно написать для этого дела тест. I>Зато в с#, C++ придется городить всякие визиторы.
И часто тебе приходится их городить? Я визиторы писал пару раз в жизни всего. Еще несколько раз пользовался готовыми.
Если уж касаться темы обхода сложных структур, то я лучше F# (статически типизированный однако) возьму, там pattern-matching есть.
G>>То есть для любой цепочки вызовов в динамическом языке нужен тест чтобы программа была не менее надежная, чем в варианте со статической типизацией. I>В итоге и там и там придется тесты писать
В динамических языках придется писать больше тестов для получения того уже уровня надежности кода.
I>а основная логика в динамическом языке будет гораздо проще читаться.
Опять-таки большая часть логики будет практически одинаково выражаться что в статике, что в динамике.
За счет чего получаются эти "гораздо" и "в разы".
Желательно на конкретном примере. Только не надо сравнивать голый C c Ruby.
Здравствуйте, kochetkov.vladimir, Вы писали:
I>>Запрограммируй на С#/С++ конечный автомат какой. Сравни с его реализацией скажем на Питоне или Руби. Сделай выводы.
KV>Давай, показывай код на питоне, сравним с тем, как это в nemerle будет выглядеть.
Здравствуйте, kochetkov.vladimir, Вы писали:
KV>Здравствуйте, Ikemefula, Вы писали:
I>>Запрограммируй на С#/С++ конечный автомат какой. Сравни с его реализацией скажем на Питоне или Руби. Сделай выводы.
KV>Давай, показывай код на питоне, сравним с тем, как это в nemerle будет выглядеть.
generator stateA
loop
while condition
do something
yield stateB
generator stateB
loop
while condition
do something
yield stateA
subroutine dispatcher
var d := new dictionary〈generator → iterator〉
d[stateA] := start stateA
d[stateB] := start stateB
var current := stateA
loop
current := next d[current]
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, kochetkov.vladimir, Вы писали:
KV>>Здравствуйте, Ikemefula, Вы писали:
I>>>Запрограммируй на С#/С++ конечный автомат какой. Сравни с его реализацией скажем на Питоне или Руби. Сделай выводы.
KV>>Давай, показывай код на питоне, сравним с тем, как это в nemerle будет выглядеть.
generator stateA
loop
while condition
do something
yield stateB
generator stateB
loop
while condition
do something
yield stateA
subroutine dispatcher
var d := new dictionary〈generator → iterator〉
d[stateA] := start stateA
d[stateB] := start stateB
var current := stateA
loop
current := next d[current]
Здравствуйте, gandjustas, Вы писали:
I>>Запрограммируй на С#/С++ конечный автомат какой. Сравни с его реализацией скажем на Питоне или Руби. Сделай выводы. G>А в чем проблема на C# сделать функцию из IEnumerable<T> в IEnumerable<V> на yield return?
Покажи пример автомата.
G>>>Если уж на то пошло, то большая часть того что пишется в динамике может быть выражена и в статике. Ну конечно зависит от языка. I>>Может и что ? G>То что утверждение про "писать в разы больше кода" несостоятельно.
В разы. Относительно С++ с его указателями так и вовсе в десятки раз.
G>>>А в случае динамического языка у тебя будет в рантайме выпадать ошибка. Причем выпадать она может не всегда. G>>>Чтобы получить надежность кода на уровне статического варианта тебе нужно написать для этого дела тест. I>>Зато в с#, C++ придется городить всякие визиторы. G>И часто тебе приходится их городить? Я визиторы писал пару раз в жизни всего. Еще несколько раз пользовался готовыми.
мне вот обходы всякие приходится писать чуть не постоянно
I>>В итоге и там и там придется тесты писать G>В динамических языках придется писать больше тестов для получения того уже уровня надежности кода.
теоретически
I>>а основная логика в динамическом языке будет гораздо проще читаться. G>Опять-таки большая часть логики будет практически одинаково выражаться что в статике, что в динамике.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, kochetkov.vladimir, Вы писали:
KV>>Nemerle:
J>Боже... Дай, думаю, посмотрю, что пишут в "Дельфи против СИ++"...
Здравствуйте, kochetkov.vladimir, Вы писали:
I>>Это Руби а не питон.
KV>P.S: Я конечно не программист, но не до такой же степени. Руби от питона в состоянии отличить, по крайней мере
Я на всякий, что бы особо быстрые на руку не нагенерили мессагов что я руби от питона не в состоянии отличить
Здравствуйте, kochetkov.vladimir, Вы писали:
J>>>>Боже... Дай, думаю, посмотрю, что пишут в "Дельфи против СИ++"... I>>Минусы за немерле, а примеры — хорошие.
KV>Минусы за немерле — это как? Я же не виноват, что именно на примере этого языка статика рвет динамику, с чем не согласен-то?
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, kochetkov.vladimir, Вы писали:
I>>>P.S. Щас вот подпись обновится и всё станет ясно
KV>>Ааааа. Я нахожу эту подпись несколько утопичной
I>Опасно ходишь !
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>Запрограммируй на С#/С++ конечный автомат какой. Сравни с его реализацией скажем на Питоне или Руби. Сделай выводы. G>>А в чем проблема на C# сделать функцию из IEnumerable<T> в IEnumerable<V> на yield return?
I>Покажи пример автомата.
G>>>>Если уж на то пошло, то большая часть того что пишется в динамике может быть выражена и в статике. Ну конечно зависит от языка. I>>>Может и что ? G>>То что утверждение про "писать в разы больше кода" несостоятельно. I>В разы. Относительно С++ с его указателями так и вовсе в десятки раз.
Ну ты еще с ассемблером сравни.
G>>>>А в случае динамического языка у тебя будет в рантайме выпадать ошибка. Причем выпадать она может не всегда. G>>>>Чтобы получить надежность кода на уровне статического варианта тебе нужно написать для этого дела тест. I>>>Зато в с#, C++ придется городить всякие визиторы. G>>И часто тебе приходится их городить? Я визиторы писал пару раз в жизни всего. Еще несколько раз пользовался готовыми. I>мне вот обходы всякие приходится писать чуть не постоянно
Обходы и визиторы — не одно и то же.
Я тоже часто пишу обходы, мне хватает IEnumerable<T> и Linq.
I>>>В итоге и там и там придется тесты писать G>>В динамических языках придется писать больше тестов для получения того уже уровня надежности кода. I>теоретически
Также как и увеличение кода, про которое ты рассказываешь.
I>>>а основная логика в динамическом языке будет гораздо проще читаться. G>>Опять-таки большая часть логики будет практически одинаково выражаться что в статике, что в динамике. I>теоретически
Также как и увеличение кода, про которое ты рассказываешь.
Можно, но твой код даже не скомпилится, т.к. надо пообъявлять State.A и тд.
Т.е. пока что ты сел в лужу
I>>>>Зато в с#, C++ придется городить всякие визиторы. G>>>И часто тебе приходится их городить? Я визиторы писал пару раз в жизни всего. Еще несколько раз пользовался готовыми. I>>мне вот обходы всякие приходится писать чуть не постоянно G>Обходы и визиторы — не одно и то же. G>Я тоже часто пишу обходы, мне хватает IEnumerable<T> и Linq.
Вот,сильно упрощенный пример. Покажи, как тут Linq поможет
IEnumerable<Vertex> Verteces(Vertex root)
{
var hash = new HashSet<Vertex>();
ListVisitor<Vertex> visitList = null;
Visitor<Vertex> visit = (v) => { hash.Add(v); visitList(v.Childs); };
visitList = (l) => { foreach(var v in l ?? new Vertex[0] ) visit(v); }
visit(root);
return hash;
}
I>>теоретически G>Также как и увеличение кода, про которое ты рассказываешь.
см выше.
I>>>>а основная логика в динамическом языке будет гораздо проще читаться. G>>>Опять-таки большая часть логики будет практически одинаково выражаться что в статике, что в динамике. I>>теоретически G>Также как и увеличение кода, про которое ты рассказываешь.
в полном варианте кроме Vertex еще куча всяких классов. Как с ними быть — не ясно. А вот в динамие — одна рекурсивная фунцыя.
G>>В принципе и на C++ можно такое же сделать.
I>Можно, но твой код даже не скомпилится, т.к. надо пообъявлять State.A и тд. I>Т.е. пока что ты сел в лужу
не включай дурачка, типа сам не догадаешься:
public enum State {A,B,C,D}
public enum Event {W,X,Y,Z}
По объему кода 1-в-1 соответствует тому что ты написан на Ruby.
В принципе и на C++ можно написать с тем же объемом.
I>>>>>Зато в с#, C++ придется городить всякие визиторы. G>>>>И часто тебе приходится их городить? Я визиторы писал пару раз в жизни всего. Еще несколько раз пользовался готовыми. I>>>мне вот обходы всякие приходится писать чуть не постоянно G>>Обходы и визиторы — не одно и то же. G>>Я тоже часто пишу обходы, мне хватает IEnumerable<T> и Linq.
I>Вот,сильно упрощенный пример. Покажи, как тут Linq поможет I>
I>IEnumerable<Vertex> Verteces(Vertex root)
I>{
I> var hash = new HashSet<Vertex>();
I> ListVisitor<Vertex> visitList = null;
I> Visitor<Vertex> visit = (v) => { hash.Add(v); visitList(v.Childs); };
I> visitList = (l) => { foreach(var v in l ?? new Vertex[0] ) visit(v); }
I> visit(root);
I> return hash;
I>}
I>
TreeNumerable.Traverse(root, v => v.Childs ?? new Vertex[0]).Distinct()
Вообще визитор оправдан когда у тебя:
1)очень развесистая иерархия классов
2)она со временем не меняется
3)классы образуют дерево
4)алгоритмы обхода дерева часто меняются
В других случаях есть более простые способы.
Вообще странно что я тебе такое рассказываю.
I>в полном варианте кроме Vertex еще куча всяких классов. Как с ними быть — не ясно. А вот в динамие — одна рекурсивная фунцыя.
Используй комбинаторы.
Здравствуйте, kochetkov.vladimir, Вы писали:
KV>Минусы за немерле — это как? Я же не виноват, что именно на примере этого языка статика рвет динамику, с чем не согласен-то?
Linq здесь ровно один вызов А кода уже больше, чем у меня Вот уж помощь так помощь
G>И твой код сокращается до G>
G>TreeNumerable.Traverse(root, v => v.Childs ?? new Vertex[0]).Distinct()
G>
А код выше куда деть ? Для частного случая у тебя получилось даже больше кода чем у меня А если вдруг окажется, что обход не только сверху вниз и классов в обходе будет больше одного, внезапно окажется, что твой код вообще не нужен
G>Вообще визитор оправдан когда у тебя:
Спасибо за информацию, КО. Только если бы ты не торопился, то не стал бы пороть очевидную чушь.
I>>в полном варианте кроме Vertex еще куча всяких классов. Как с ними быть — не ясно. А вот в динамие — одна рекурсивная фунцыя. G>Используй комбинаторы.
Шо ж ты сам их не показл преимущества этих комбинаторов ? Увлёкся, вероятно
P.S. Похоже, у меня в коде фатальный недостаток — мой код пиcан не тобой
I>Linq здесь ровно один вызов А кода уже больше, чем у меня Вот уж помощь так помощь
1)Это универсальный код, в отличие от твоего, написан один раз и используется всегда
2)Этот код работает лениво, в отличие от твоего
G>>И твой код сокращается до G>>
G>>TreeNumerable.Traverse(root, v => v.Childs ?? new Vertex[0]).Distinct()
G>>
I>А код выше куда деть? Для частного случая у тебя получилось даже больше кода чем у меня А если вдруг окажется, что обход не только сверху вниз и классов в обходе будет больше одного, внезапно окажется, что твой код вообще не нужен
Приведи пример, тогда посмотрим.
G>>Вообще визитор оправдан когда у тебя: I>Спасибо за информацию, КО. Только если бы ты не торопился, то не стал бы пороть очевидную чушь.
Так ты спрашиваешь очевидные вещи и совершаешь банальные ошибки.
I>>>в полном варианте кроме Vertex еще куча всяких классов. Как с ними быть — не ясно. А вот в динамие — одна рекурсивная фунцыя. G>>Используй комбинаторы. I>Шо ж ты сам их не показл преимущества этих комбинаторов ? Увлёкся, вероятно
А Traverse это что по твоему?
I>P.S. Похоже, у меня в коде фатальный недостаток — мой код пиcан не тобой
Нет, фатальный недостаток у тебя в том что ты начинаешь выкручиваться вместо того чтобы понять где ты неправ.
PS. Пойди еще скажи тем кто Rx написал, что они неправы, потому что они написали очень много кода, который позволит сократить твой код на 2 строчки.
Здравствуйте, gandjustas, Вы писали:
I>>Linq здесь ровно один вызов А кода уже больше, чем у меня Вот уж помощь так помощь G>1)Это универсальный код, в отличие от твоего, написан один раз и используется всегда
Твой код для частного случая, когда нужно только по вертексам и только сверху вниз бегать.
G>2)Этот код работает лениво, в отличие от твоего
И ты уверен, что всегда нужна эта ленивость ?
G>>>И твой код сокращается до G>>>
G>>>TreeNumerable.Traverse(root, v => v.Childs ?? new Vertex[0]).Distinct()
G>>>
I>>А код выше куда деть? Для частного случая у тебя получилось даже больше кода чем у меня А если вдруг окажется, что обход не только сверху вниз и классов в обходе будет больше одного, внезапно окажется, что твой код вообще не нужен
G>Приведи пример, тогда посмотрим.
Слишком большой пример получается а ты постоянно спрыгиваешь на свои задачи. В общих чертах примерно так — иерархическая структура, которую нужно обойти при чем некоторые объекты нужно обходить по нескольку раз. Как выделить более менее адекватный пример — пока не знаю и времени на это нет.
I>>>>в полном варианте кроме Vertex еще куча всяких классов. Как с ними быть — не ясно. А вот в динамие — одна рекурсивная фунцыя. G>>>Используй комбинаторы. I>>Шо ж ты сам их не показл преимущества этих комбинаторов ? Увлёкся, вероятно G>А Traverse это что по твоему?
Это частный случай который больше никуде не приспособить
G>PS. Пойди еще скажи тем кто Rx написал, что они неправы, потому что они написали очень много кода, который позволит сократить твой код на 2 строчки.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>Linq здесь ровно один вызов А кода уже больше, чем у меня Вот уж помощь так помощь G>>1)Это универсальный код, в отличие от твоего, написан один раз и используется всегда
I>Твой код для частного случая, когда нужно только по вертексам и только сверху вниз бегать.
Ок, приведи код с визитором, в котором надо как-то по-другому бегать.
G>>2)Этот код работает лениво, в отличие от твоего I>И ты уверен, что всегда нужна эта ленивость ?
Там где не нужна будет я напишу ToList, а ты что сделаешь чтобы получить ленивость в своем коде?
G>>>>И твой код сокращается до G>>>>
G>>>>TreeNumerable.Traverse(root, v => v.Childs ?? new Vertex[0]).Distinct()
G>>>>
I>>>А код выше куда деть? Для частного случая у тебя получилось даже больше кода чем у меня А если вдруг окажется, что обход не только сверху вниз и классов в обходе будет больше одного, внезапно окажется, что твой код вообще не нужен
G>>Приведи пример, тогда посмотрим.
I>Слишком большой пример получается а ты постоянно спрыгиваешь на свои задачи.
Да ну?
Ты привел код, а когда я привел свой вариант, делающий ровно тоже самое, но с большим потенциалом повторного использования и композиции ты сказал:
I>Твой код для частного случая, когда нужно только по вертексам и только сверху вниз бегать.
А до этого пытался оправдать непонятно зачем написанный недовизитор тем что у тебя "еще куча всего".
I>в полном варианте кроме Vertex еще куча всяких классов.
Более того, ты завел разговор о визиторах, хотя зачем там визиторы — так и не смог показать.
I>Зато в с#, C++ придется городить всякие визиторы.
I>В общих чертах примерно так — иерархическая структура которую нужно обойти при чем некоторые объекты нужно обходить по нескольку раз. Как выделить более менее адекватный пример — пока не знаю и времени на это нет.
Ну значит считаем что с визиторами ты сел в лужу, пока не доказано обратного.
I>>>>>в полном варианте кроме Vertex еще куча всяких классов. Как с ними быть — не ясно. А вот в динамие — одна рекурсивная фунцыя. G>>>>Используй комбинаторы. I>>>Шо ж ты сам их не показл преимущества этих комбинаторов ? Увлёкся, вероятно G>>А Traverse это что по твоему? I>Это частный случай который больше никуде не приспособить
1)Не уходи от вопроса. Ты не считаешь Visitor комбинатором?
2)Он позволяет обойти любое дерево, где узел хранит ссылки на потомков
3)Так как обход делается лениво, то это позволяет без проблем комбинировать его с другими
Здравствуйте, gandjustas, Вы писали:
G>>>2)Этот код работает лениво, в отличие от твоего I>>И ты уверен, что всегда нужна эта ленивость ? G>Там где не нужна будет я напишу ToList, а ты что сделаешь чтобы получить ленивость в своем коде ?
Ты свой код сам писал ? foreach что у тебя делает ? Опаньки, ленивость вышла кастрированая Но вообще ленивость в моем случае всегда замедление, что недопустимо в принципе.
G>>>Приведи пример, тогда посмотрим.
I>>Слишком большой пример получается а ты постоянно спрыгиваешь на свои задачи. G>Да ну?
Ну да.
G>Ты привел код, а когда я привел свой вариант, делающий ровно тоже самое, но с большим потенциалом повторного использования и композиции ты сказал:
А для чего в частном случае целая куча кода как у тебя да еще с сайд-эффектами в виде недоленивости и проседания перформанса ?
G>А до этого пытался оправдать непонятно зачем написанный недовизитор тем что у тебя "еще куча всего".
И что тебя смущает ? Код завязан на определенную специфику и нет времени адаптировать его персонально для тебя.
G>Более того, ты завел разговор о визиторах, хотя зачем там визиторы — так и не смог показать.
Выполнять операции над конкретной структурой, это ж очевидно. В операциях оных всегда нужен обход какой нибудь.
I>>Это частный случай который больше никуде не приспособить G>2)Он позволяет обойти любое дерево, где узел хранит ссылки на потомков
Твой вариант удобен только для однородной структуры, т.е. частный случай.
G>3)Так как обход делается лениво, то это позволяет без проблем комбинировать его с другими
Во первых, ленивость у тебя кастрированая. Во вторых, у тебя частный случай. В третьих проблемы в виде проседания перформанса в несколько раз. В четвертых, гнусная отладка получается с твоими "комбинаторами".
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
G>>>>2)Этот код работает лениво, в отличие от твоего I>>>И ты уверен, что всегда нужна эта ленивость ? G>>Там где не нужна будет я напишу ToList, а ты что сделаешь чтобы получить ленивость в своем коде ?
I>Ты свой код сам писал ? foreach что у тебя делает ? Опаньки, ленивость вышла кастрированая
Ты о чем вообще? Нормальная там ленивость. Ты настолько плохо разбираешься в итераторах?
I>Но вообще ленивость в моем случае всегда замедление, что недопустимо в принципе.
Придать "энергичность" ленивому коду легко, наоборот — нет.
G>>>>Приведи пример, тогда посмотрим.
I>>>Слишком большой пример получается а ты постоянно спрыгиваешь на свои задачи. G>>Да ну? G>>Ты привел код, а когда я привел свой вариант, делающий ровно тоже самое, но с большим потенциалом повторного использования и композиции ты сказал: I>А для чего в частном случае целая куча кода как у тебя да еще с сайд-эффектами в виде недоленивости и проседания перформанса ?
Ладно, то что ты не понимаешь C# кое-где я уже понял. И сайд-эффектами ты тоже называешь непонятно что.
Кроме того ты совершенно не к месту притянул перформанс. Надо бы его померить, а потом говорить.
G>>А до этого пытался оправдать непонятно зачем написанный недовизитор тем что у тебя "еще куча всего". I>И что тебя смущает ? Код завязан на определенную специфику и нет времени адаптировать его персонально для тебя.
Я тебе показал более общий код, который делает тоже самое
G>>Более того, ты завел разговор о визиторах, хотя зачем там визиторы — так и не смог показать. I>Выполнять операции над конкретной структурой, это ж очевидно. В операциях оных всегда нужен обход какой нибудь.
Так ты и не показал визитор, показал рекурсивную функцию с замыканием.
I>>>Это частный случай который больше никуде не приспособить G>>2)Он позволяет обойти любое дерево, где узел хранит ссылки на потомков I>Твой вариант удобен только для однородной структуры, т.е. частный случай.
Я привел пример в соответствие с твоим кодом.
G>>3)Так как обход делается лениво, то это позволяет без проблем комбинировать его с другими
I>Во первых, ленивость у тебя кастрированая.
Не говорил бы глупостей.
I>Во вторых, у тебя частный случай.
Более общий, чем ты привел.
I>В третьих проблемы в виде проседания перформанса в несколько раз.
Мерить надо.
I>В четвертых, гнусная отладка получается с твоими "комбинаторами".
А думаешь с рекурсивными вызовами анонимных функций, что ты привел, получается проще.
Хочешь что-то показать — приводи реальный код. А так все мои высказывания опираются на то что ты привел. Если то что ты привел не соотвествует тому что ты делаешь на самом деле — твои проблемы.
Здравствуйте, gandjustas, Вы писали:
I>>Ты свой код сам писал ? foreach что у тебя делает ? Опаньки, ленивость вышла кастрированая G>Ты о чем вообще? Нормальная там ленивость. Ты настолько плохо разбираешься в итераторах?
Да, я сегодня не выспался шота Есть ошибка, которая вобщем то и у меня в наличии — HashSet нужен для завершения рекурсии.
Тебя, вероятно ввело в заблуждение слово Childs, правильнее назвать Connections.
Вот, нужно добавить:
Назначение функции — вычислить подграф c определенным порядком следования вертексов, для чего используется модифицированый dfs
I>>В третьих проблемы в виде проседания перформанса в несколько раз. G>Мерить надо.
Уже измерено. Разброс есть, правда не такой, как говорит Дворкин, но есть и это очень неприятно, т.к. все это влияет на время отклика.
I>>В четвертых, гнусная отладка получается с твоими "комбинаторами". G>А думаешь с рекурсивными вызовами анонимных функций, что ты привел, получается проще.
Конечно проще, весь обход — перед глазами.
G>Хочешь что-то показать — приводи реальный код. А так все мои высказывания опираются на то что ты привел.
Вот фунцыя, находит все роуты в подграфе вершиной которого является root, снова модифицированый dfs. Покажи мне Linq и Комбинаторы
IEnumerable<Route> AllRoutes(Vertex root)
{
var hash = new HashSet<Vertex>();
var route = new List<Vertex>();
var routes = new List<Route>();
ListVisitor<Vertex> visitList = null;
Visitor<Vertex> visit = (v) =>
{
if(hash.Contains(v))
{
routes.Add(new Route(route));
return;
}
route.Add(v);
hash.Add(v);
routes.Add(new Route(route));
visitList(v.Childs);
route.RemoveLast(); // как ты это обойдешь, не ясно
};
visitList = (l) => { foreach(var v in l ?? new Vertex[0] ) visit(v); }
visit(root);
return routes;
}
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Это не паттерн Visitor, а какая то фигня. Паттерн используется, когда нужна диспетчеризация по типам с общим корнем.
На статическом полиморфизме визитор тоже прекрасно работает, например в С++.
Здравствуйте, Ikemefula, Вы писали:
I>С таким подходом вообще все получается цельнотянутым из ФП
ВЫ неправильно делаете, что обсуждаете какие-то цитаты. Не важно, откуда взялась идея начального дизайна, важно, какой дизайн вышел в итоге. Он вышел в стиле ФП, кто бы что ни говорил. И библиотеки буста тоже по большей части идут в ФП стиле.
Здравствуйте, Ikemefula, Вы писали:
I>Вообще говоря визитор это не только когда диспетчеризация по типам с общим корнем.
Вообще говоря только. По определению.
... the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves; instead, one creates a visitor class that implements all of the appropriate specializations of the virtual function. The visitor takes the instance reference as input, and implements the goal through double dispatch.
Википедия
А вот откуда взялось поверье, что визитор это обход графа для меня загадка.
Здравствуйте, vdimas, Вы писали:
НС>>Это не паттерн Visitor, а какая то фигня. Паттерн используется, когда нужна диспетчеризация по типам с общим корнем.
V>На статическом полиморфизме визитор тоже прекрасно работает, например в С++.
Статический полиморфизм это уже не визитор, и даже не может являтся его заменой. Как не может статическая перегрузка методов быть заменой мультиметодов.
Откуда вообще эта стратсть натягивать презерватив на ежика? Визитор — вполне конкретный паттерн, описанный изначально в GoF. При этом может существует несколько видов задач диспетчеризации и несколько методов решения этих задач, но визиторами они от этого не становятся.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Откуда вообще эта стратсть натягивать презерватив на ежика?
Так оно круче звучит и создаёт иллюзию безопасного ёжика понимания предмета.
I>>>В четвертых, гнусная отладка получается с твоими "комбинаторами". G>>А думаешь с рекурсивными вызовами анонимных функций, что ты привел, получается проще.
I>Конечно проще, весь обход — перед глазами.
Только непонятно нифига. А обобщенный комбинатор пишется и отлаживается ровно один раз.
G>>Хочешь что-то показать — приводи реальный код. А так все мои высказывания опираются на то что ты привел.
I>Вот фунцыя, находит все роуты в подграфе вершиной которого является root, снова модифицированый dfs.
Кто такие роуты? В твоем коде черт ногу сломит. Рекурсия + mutable state читаемость снижают до нуля.
Здравствуйте, gandjustas, Вы писали:
G>И чем он оправдан там где сложность? G>Скорее наоборот. Сложность реализации простых вещей оправдывается языком C++, но при этом во всю говорят о том как это эффективно.
Почему, когда другие языки имитируют (обычно с потерей эффективности) фичи C++, такие как метапрограммирование, переопределение операторов,
объекты STL — это "круто", а С++ "слишком сложный"?
Черт возьми, ну не для всех он "слишком сложный"...
Здравствуйте, Head Ache, Вы писали:
HA>Здравствуйте, gandjustas, Вы писали:
G>>И чем он оправдан там где сложность? G>>Скорее наоборот. Сложность реализации простых вещей оправдывается языком C++, но при этом во всю говорят о том как это эффективно.
HA>Почему, когда другие языки имитируют (обычно с потерей эффективности) фичи C++, такие как метапрограммирование, переопределение операторов,
С чего это переопределение операторов — фича C++? Эта фича во многих языках была и до C++ и есть во многих после.
HA>объекты STL — это "круто", а С++ "слишком сложный"?
STL как раз упрощает C++: по-максимуму прячет указатели, реализацию строк и работу с динамической памятью. Это как раз те аспекты С++, которые делают его переусложненным.
Здравствуйте, vdimas, Вы писали:
V>ВЫ неправильно делаете, что обсуждаете какие-то цитаты. Не важно, откуда взялась идея начального дизайна, важно, какой дизайн вышел в итоге. Он вышел в стиле ФП, кто бы что ни говорил. И библиотеки буста тоже по большей части идут в ФП стиле.
Здравствуйте, Ночной Смотрящий, Вы писали:
I>>Вообще говоря визитор это не только когда диспетчеризация по типам с общим корнем.
НС>Вообще говоря только. По определению.
Чушь. Открываешь любую книгу и читаешь — операции над объектной структурой. Общий корень может быть а может и не быть. А вот двойная диспетчеризация будет обязательно.
НС>Википедия
После таких аргументов ... Но если ты прочтешь тобой же написано, то окажется, что общий корень вовсе необязательно.
НС>А вот откуда взялось поверье, что визитор это обход графа для меня загадка.
Процитируй, уважаемый Трепло, где же я такое сказал.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Статический полиморфизм это уже не визитор, и даже не может являтся его заменой.
Википедию поменьше читай.
НС>Откуда вообще эта стратсть натягивать презерватив на ежика? Визитор — вполне конкретный паттерн, описанный изначально в GoF.
В ГОФ он изложен достаточно гнусно, как и многие другие паттерны.
Здравствуйте, Ikemefula, Вы писали:
I>Чушь. Открываешь любую книгу и читаешь — операции над объектной структурой
Под это определение подходят чуть болеечем все поведенческие паттерны
Ну да цитату в студию. Лучше всего из банды, первоисточник все таки.
I>. Общий корень может быть а может и не быть. А вот двойная диспетчеризация будет обязательно.
С точностью до наоборот.
I>После таких аргументов ...
I> Но если ты прочтешь тобой же написано, то окажется, что общий корень вовсе необязательно.
В общем случае — нет, в шарпе — обязателен (до C# 4 по крайней мере). Потому что для общего виртуального метода необходим общий корень.
НС>>А вот откуда взялось поверье, что визитор это обход графа для меня загадка.
I>Процитируй, уважаемый Трепло, где же я такое сказал.
Здравствуйте, gandjustas, Вы писали:
I>>Конечно проще, весь обход — перед глазами.
G>Только непонятно нифига. А обобщенный комбинатор пишется и отлаживается ровно один раз.
Я и вижу — ошибку в своем коде ты не смог пофиксить
Комбинаторы нужны, только от linq в конкретном примере толку не будет. Комбинатор, который фильтрует роуты которые поглощают другие роуты вполне пригодится но это опять же без linq.
G>>>Хочешь что-то показать — приводи реальный код. А так все мои высказывания опираются на то что ты привел.
I>>Вот фунцыя, находит все роуты в подграфе вершиной которого является root, снова модифицированый dfs. G>Кто такие роуты? В твоем коде черт ногу сломит. Рекурсия + mutable state читаемость снижают до нуля.
Там все очевидно, если ты знаешь что такое dfs. В данном случае mutable state не вносит никакой проблемы/
И заметь — как дело дошло до реального примера, ты в очередной раз сдулся. На будущее — не проси у меня примеров кода.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>Конечно проще, весь обход — перед глазами.
G>>Только непонятно нифига. А обобщенный комбинатор пишется и отлаживается ровно один раз.
I>Я и вижу — ошибку в своем коде ты не смог пофиксить
Где там ошибка, ткни пальцем.
G>>>>Хочешь что-то показать — приводи реальный код. А так все мои высказывания опираются на то что ты привел.
I>>>Вот фунцыя, находит все роуты в подграфе вершиной которого является root, снова модифицированый dfs. G>>Кто такие роуты? В твоем коде черт ногу сломит. Рекурсия + mutable state читаемость снижают до нуля. I>Там все очевидно, если ты знаешь что такое dfs. В данном случае mutable state не вносит никакой проблемы/
Я отлично знаю что такое dfs, но разобраться с твоим кодом за 5 минут не смог, а на больше меня не хватило.
I>И заметь — как дело дошло до реального примера, ты в очередной раз сдулся. На будущее — не проси у меня примеров кода.
Я же говорю — напиши по-русски что делает. Потому что я не понял какую задачу решает код. А пляски с анонимными рекурсивными функциями меня мало интересуют.
Ты кстати опять прячешь знания за терминологией. Ты уже промахнулся с визиторами, теперь повторяешь про bfs, но не говоришь зачем этот bfs нужен.
Здравствуйте, gandjustas, Вы писали:
G>>>Только непонятно нифига. А обобщенный комбинатор пишется и отлаживается ровно один раз.
I>>Я и вижу — ошибку в своем коде ты не смог пофиксить G>Где там ошибка, ткни пальцем.
Я внятно объяснил и даже ткнул пальцем
Есть ошибка, которая вобщем то и у меня в наличии — HashSet нужен для завершения рекурсии.
Тебя, вероятно ввело в заблуждение слово Childs, правильнее назвать Connections.
Вот, нужно добавить:
Visitor<Vertex> visit = (v) => {if(hash.Contains(v)) return; hash.Add(v); visitList(v.Childs); };
Соответсвенно эту же корректировку нужно делать и в твоем случае, иначе обход никогда не завершится.
I>>Там все очевидно, если ты знаешь что такое dfs. В данном случае mutable state не вносит никакой проблемы/ G>Я отлично знаю что такое dfs, но разобраться с твоим кодом за 5 минут не смог, а на больше меня не хватило.
Я заметил
I>>И заметь — как дело дошло до реального примера, ты в очередной раз сдулся. На будущее — не проси у меня примеров кода. G>Я же говорю — напиши по-русски что делает. Потому что я не понял какую задачу решает код. А пляски с анонимными рекурсивными функциями меня мало интересуют.
Ты и читать похоже разучился:
"Назначение функции — вычислить подграф c определенным порядком следования вертексов, для чего используется модифицированый dfs"
"Вот фунцыя, находит все роуты в подграфе вершиной которого является root, снова модифицированый dfs. Покажи мне Linq и Комбинаторы "
G>Ты кстати опять прячешь знания за терминологией. Ты уже промахнулся с визиторами, теперь повторяешь про bfs, но не говоришь зачем этот bfs нужен.
А ты прочесть попробуй. С визиторами я не промахнулся, кстати говоря.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, Ikemefula, Вы писали:
I>>Чушь. Открываешь любую книгу и читаешь — операции над объектной структурой
НС>Под это определение подходят чуть болеечем все поведенческие паттерны
Чушь.
НС>Ну да цитату в студию. Лучше всего из банды, первоисточник все таки.
Там кривое изложение. Что мешает работать с помощью визитора над структурой состоящей из N иерархий ? Вероятно в твоем случае это идеология, потому что ты ГоФ понял буквально.
I>>. Общий корень может быть а может и не быть. А вот двойная диспетчеризация будет обязательно.
НС>С точностью до наоборот.
В некоторых источниках визитор вообще сводится к двойной диспетчеризации.
Двойная диспетчеризация не нужна в динамических языках и языках с PM. В них и визитор вообще не нужен.
I>> Но если ты прочтешь тобой же написано, то окажется, что общий корень вовсе необязательно.
НС>В общем случае — нет, в шарпе — обязателен (до C# 4 по крайней мере). Потому что для общего виртуального метода необходим общий корень.
Виртуальный метод необязателен Утиной типизации может быть достаточно, еще можно быть достаточно простой матрицы если методов и типов очень много.
I>>Процитируй, уважаемый Трепло, где же я такое сказал.
НС>Я не про тебя, неуважаемое Хамло.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, Ночной Смотрящий, Вы писали:
I>>>Вообще говоря визитор это не только когда диспетчеризация по типам с общим корнем.
НС>>Вообще говоря только. По определению.
I>Чушь. Открываешь любую книгу и читаешь — операции над объектной структурой. Общий корень может быть а может и не быть. А вот двойная диспетчеризация будет обязательно.
Давай пойдем от обратного. Представим что нет ничего общего между различными типам A, B и надо выполнить обход структуры, которую они представляют.
Для общности представим что каждый из типов A и B имеет ссылки на объекты типов A и B.
Далее как будет выглядеть обход. Так как нет общего предка, то будет две точки входа: функции VisitA и VisitB. При обходе каждая из них будет вызывать isitA и VisitB при необходимости.
Ну вот и нету двойной диспетчеризации, даже одинарной нет. Если конечно воспользоваться статическим полиморфизмом, то вполне можно сделать статическую одинарную диспетчеризацию, но это совершенно необязательно.
Кстати для визитора в определении GOF двойная диспетчеризация — не цель, а средство. Цель — отвязать операции со структурой от самой структуры, чтобы операции можно было менять произвольно.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
G>>>>Только непонятно нифига. А обобщенный комбинатор пишется и отлаживается ровно один раз.
I>>>Я и вижу — ошибку в своем коде ты не смог пофиксить G>>Где там ошибка, ткни пальцем.
I>Я внятно объяснил и даже ткнул пальцем
I>
I>Есть ошибка, которая вобщем то и у меня в наличии — HashSet нужен для завершения рекурсии.
I>Тебя, вероятно ввело в заблуждение слово Childs, правильнее назвать Connections.
I>Вот, нужно добавить:
I>Visitor<Vertex> visit = (v) => {if(hash.Contains(v)) return; hash.Add(v); visitList(v.Childs); };
I>Соответсвенно эту же корректировку нужно делать и в твоем случае, иначе обход никогда не завершится.
Нафига мне за твоими изменениями гоняться? Ты так можешь в каждом посте ченить придумывать и будешь делать вид что всегда прав.
I>>>И заметь — как дело дошло до реального примера, ты в очередной раз сдулся. На будущее — не проси у меня примеров кода. G>>Я же говорю — напиши по-русски что делает. Потому что я не понял какую задачу решает код. А пляски с анонимными рекурсивными функциями меня мало интересуют.
I>Ты и читать похоже разучился: I>"Назначение функции — вычислить подграф c определенным порядком следования вертексов, для чего используется модифицированый dfs"
"вычислить подграф c определенным порядком следования вертексов" вот это сформулируй в проверяемом виде. А то я тебе ченить напишу, а ты опять 30 раз условие поменяешь.
I>С визиторами я не промахнулся, кстати говоря. Очень промахнулся. Ты даже не можешь толково объяснить где у тебя в коде визитор. Потому что под определение GOF он не подходит, а под те определения, которые ты придумываешь (кстати ссылку на источник хотелось бы видеть) подходит то, что даже отдаленно не является визитором.
Хотя если ты называешь визитором вообще любой обход любой нетривиальной структуры, то см выделенное выше.
Здравствуйте, gandjustas, Вы писали:
I>>Соответсвенно эту же корректировку нужно делать и в твоем случае, иначе обход никогда не завершится. G> G>Нафига мне за твоими изменениями гоняться? Ты так можешь в каждом посте ченить придумывать и будешь делать вид что всегда прав.
Это не изменения, hashset был изначально.
I>>Ты и читать похоже разучился: I>>"Назначение функции — вычислить подграф c определенным порядком следования вертексов, для чего используется модифицированый dfs" G>"вычислить подграф c определенным порядком следования вертексов" вот это сформулируй в проверяемом виде. А то я тебе ченить напишу, а ты опять 30 раз условие поменяешь.
уже был даден скорректированый код, а тебе всё чего то неймется.
I>>С визиторами я не промахнулся, кстати говоря. G>Очень промахнулся. Ты даже не можешь толково объяснить где у тебя в коде визитор. Потому что под определение GOF он не подходит,
Не валяй дурака, вот после чего появился тот код
G>>Обходы и визиторы — не одно и то же.
G>>Я тоже часто пишу обходы, мне хватает IEnumerable<T> и Linq.
I>Вот,сильно упрощенный пример. Покажи, как тут Linq поможет
Очевидно, речь про обход. Я и привел тебе пример обхода, что бы ты показал куда там Linq приспособить.
А вот паттерн визитор в этом коде захотел углядеть НС, а не я.
Здравствуйте, gandjustas, Вы писали:
G>Далее как будет выглядеть обход. Так как нет общего предка, то будет две точки входа: функции VisitA и VisitB. При обходе каждая из них будет вызывать isitA и VisitB при необходимости.
G>Ну вот и нету двойной диспетчеризации, даже одинарной нет. Если конечно воспользоваться статическим полиморфизмом, то вполне можно сделать статическую одинарную диспетчеризацию, но это совершенно необязательно.
В частном случае это так. А если, скажем, будет нечто вроде коллекции List<object> которая будет хранить и A и B ?
Итого — в частных случаях двойная диспетчеризация не нужна. В общем — нужна.
Здравствуйте, Ikemefula, Вы писали:
I>>>Ты и читать похоже разучился: I>>>"Назначение функции — вычислить подграф c определенным порядком следования вертексов, для чего используется модифицированый dfs" G>>"вычислить подграф c определенным порядком следования вертексов" вот это сформулируй в проверяемом виде. А то я тебе ченить напишу, а ты опять 30 раз условие поменяешь.
I>уже был даден скорректированый код, а тебе всё чего то неймется.
То есть ты не хочешь рассказать что он делает (как он что-то делает я уже вижу)?
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
G>>Далее как будет выглядеть обход. Так как нет общего предка, то будет две точки входа: функции VisitA и VisitB. При обходе каждая из них будет вызывать isitA и VisitB при необходимости.
G>>Ну вот и нету двойной диспетчеризации, даже одинарной нет. Если конечно воспользоваться статическим полиморфизмом, то вполне можно сделать статическую одинарную диспетчеризацию, но это совершенно необязательно.
I>В частном случае это так. А если, скажем, будет нечто вроде коллекции List<object> которая будет хранить и A и B ?
То есть ты ввел общего предка "object". Но у тебя также будет одинарная диспетчеризация через type testing будет, а не двойная.
Ты создал частный случай, я как раз описал более общий случай.
I>Итого — в частных случаях двойная диспетчеризация не нужна. В общем — нужна.
Это ты приводишь частный случай Ведь в C++ такого не напишешь, там нет общего предка.
I>Иди читай дальше
Это ты иди со своими заказчиками так общайся, тут "приседание на умняк" не помогает. Ты аргументов не приводишь, только увиливаешь.
Здравствуйте, gandjustas, Вы писали:
I>>уже был даден скорректированый код, а тебе всё чего то неймется. G>То есть ты не хочешь рассказать что он делает (как он что-то делает я уже вижу)?
Это ж очевидно — находит и возвращает все вертексы достижимые из заданного.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>уже был даден скорректированый код, а тебе всё чего то неймется. G>>То есть ты не хочешь рассказать что он делает (как он что-то делает я уже вижу)?
I>Это ж очевидно — находит и возвращает все вертексы достижимые из заданного.
Ну держи:
public static IEnumerable<T> BreadthFirst<T>(T item, Func<T, IEnumerable<T>> ajancedNodes)
{
return BreadthFirstImpl(ajancedNodes(item), ajancedNodes, new HashSet<T>());
}
private static IEnumerable<T> BreadthFirstImpl<T>(IEnumerable<T> nodes, Func<T, IEnumerable<T>> ajancedNodes, HashSet<T> visited)
{
var l = nodes.Where(visited.Add).ToList();
if (!l.Any())
{
return Enumerable.Empty<T>();
}
var seq = l.SelectMany(ajancedNodes);
return l.Concat(EnumerableEx.Defer(() => BreadthFirstImpl(seq, ajancedNodes, visited)));
}
IEnumerable<Vertex> Reachable(Vertex vertex)
{
return BreadthFirst(vertex, v => v.Childs ?? new Vertex[0]);
}
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
G>>Ну держи:
I>Т.е. количество кода у тебя тупо увеличилось в полтора раза
А мне студия говорит что у меня 11 строк против твоих 16
Я ей больше верю.
I>При этом I>вместо dfs ты взял bfs, я понимаю, что ты специально "забыл", ну да хрен с ним
Опять ты за свое...
I>>находит и возвращает все вертексы достижимые из заданного.
Это условие выполняется.
I>перформанс падает ниже плинтуса в BreadthFirstImpl
А как ты померил? Покажи тестовые данные, результаты забегов итп.
I>ЧТД — на JS том же задача решается в 5 строк, у тебя — 18 из за Linq. Вобщем, ты показал, что на динамике и код короче и прозрачнее
См выше. Ты не те строки считаешь.
Кстати покажи код на js, я тебе не верю что 5 строк будет. Хотя смотря какие строки ты считаешь в js.
I>P.S. А теперь попробуй решить вторую задачу, для которой я привел свое решение, — поиск всех роутов начиная с заданного вертекса.
Нивопрос, выбирай
public static IEnumerable<IEnumerable<T>> BreadthFirst<T>(T item, Func<T, IEnumerable<T>> adjacentNodes)
{
var p = EnumerableEx.Return(item);
var visited = new HashSet<T>(p);
return EnumerableEx.Generate(EnumerableEx.Return(p),
s => s.Any(),
s => (from ss in s
from n in adjacentNodes(ss.First())
where visited.Add(n)
select ss.StartWith(n)).MemoizeAll(),
s => s
).SelectMany(s => s);
}
public static IEnumerable<IEnumerable<T>> DepthFirst<T>(T item, Func<T, IEnumerable<T>> adjacentNodes)
{
var p = EnumerableEx.Return(item);
var visited = new HashSet<T>(p);
return DepthFirstImpl(p, adjacentNodes, visited).MemoizeAll();
}
private static IEnumerable<IEnumerable<T>> DepthFirstImpl<T>(IEnumerable<T> path, Func<T, IEnumerable<T>> adjacentNodes, HashSet<T> visited)
{
return adjacentNodes(path.First())
.Where(visited.Add)
.SelectMany(n => DepthFirstImpl(path.StartWith(n), adjacentNodes, visited))
.StartWith(path);
}
IEnumerable<Route> AllRoutes1(Vertex root)
{
return BreadthFirst(root, v => v.Childs ?? new Vertex[0])
.Select(r => new Route(r.Reverse()));
}
IEnumerable<Route> AllRoutes2(Vertex root)
{
return DepthFirst(root, v => v.Childs ?? new Vertex[0])
.Select(r => new Route(r.Reverse()));
}
I>P.P.S. фунцыя в JS V8 походу порвёт твой _шедевр_ по перформансу.
Нивопрос, приведи реальную задачу и тестовые данные.
Я специально сделал поиск максимально ленивым, чтобы мог при желании ограничить перебор и даже не искать все пути на графе.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Визитор — вполне конкретный паттерн, описанный изначально в GoF.
За это минус, ибо ни в какие ворота... Все "трюки", описанные в GOF были известны задолго до. GOF известен тем, что обобщил и что дал терминологию трюкам, ну и дохочиво, "на пальцах", разъяснил подходящие условия для применения упомянутых паттернов.
Визитор — это трюк всегда известный под названием двойной диспетчеризации. Кто бы что ни говорил, утверждая, что это "другая точка зрения на происходящее". Словесная муть это, а не "другая точка зрения".
НС>При этом может существует несколько видов задач диспетчеризации и несколько методов решения этих задач, но визиторами они от этого не становятся.
Мде... Если правый аргумент называется visitor, то это, понятное дело, одноименный паттерн, а если этот же аргумент назвать callMeBack, то уже совсем другое дело, ага, это уже разновидность диспетчеризации.
ИМХО, это от непонимания концепции мультиметодов (частный случай которых в 2-х аргументах веселая четверка обозвала визитором, хотя суть паттерна "визитор" может быть расширена на любое кол-во аргументов, ибо это позволяют мультиметоды).
НС>Как не может статическая перегрузка методов быть заменой мультиметодов.
Да мы уже поняли, что кто-то ничего не понял. Речь не о статической перегрузке сигнатур ф-ий или методов. Именно как в "классическом" визиторе речь о диспатчинге в рантайм, например в boost::variant конкретный метод обратного вызова зависит от текущего хранимого типа. Вся разница в том, что при этом вызываемые методы визитора не обязаны быть виртуальными, потому как идет кодогенерация на шаблонах прямо в конкретном месте обратного вызова (кода посетителя) с уточненным типом-визитором. Сравни с неуточненным в случае интерфейсов. В "неуточненном" варианте исполнения предполагается только одна реализация визитора, которая абстрагируется от конкретного посещаемого через интерфейс. А в С++ имеем кодогенерацию на шаблонах произвольного кол-ва этих методов под конкретные типы. И да, классический интерфейс с виртуальными ф-иями тоже можно подавать. В этом случае будет сгенерен тот же код, который может быть написан в необобщенном виде, на абстрактных классах/интерфейсах, например на Джаве времен GOF.
Посмотри на этот boost::variant, должно стать понятней, что имеют ввиду, когда говорят про "статического визитора" в С++. В C# такого на генериках не получить, там потребуется именно некий интерфейс, требующий последующего переопределения, то бишь потребуется техника виртуальных ф-ий. А вот в современной Джаве, скорее всего, уже можно.
Здравствуйте, Sinix, Вы писали:
НС>>Откуда вообще эта стратсть натягивать презерватив на ежика? S>Так оно круче звучит и создаёт иллюзию безопасного ёжика понимания предмета.
Дык, вроде статическая типобезопасность круче динамической?
Здравствуйте, Ikemefula, Вы писали:
НС>>Под это определение подходят чуть болеечем все поведенческие паттерны
I>Чушь.
Веско
НС>>Ну да цитату в студию. Лучше всего из банды, первоисточник все таки.
I>Там кривое изложение.
Давай источник с прямым.
НС>>С точностью до наоборот.
I>В некоторых источниках визитор вообще сводится к двойной диспетчеризации.
В языках с отсутствующей перегрузкой допустимо использование рукопашного разнесения по нужным методам. Да и в языках с онной иногда, для улучшения читаемости, от двойной диспетчеризации отказываются. Главное, это никак не меняет логику самого паттерна, всего лишь определяет, какую часть работы возьмет на себя компилятор.
I>Виртуальный метод необязателен Утиной типизации может быть достаточно
Что в лоб, что по лбу. Но пример то у тебя на шарпе, там никакой утиной типизации в статически типизированном контексте нет.
I>Отвечаешь мне, а пишешь не мне
Такое иногда бывает, да. Тут все таки не личная переписка, а публичный форум.
Здравствуйте, gandjustas, Вы писали:
G>Кстати для визитора в определении GOF двойная диспетчеризация — не цель, а средство. Цель — отвязать операции со структурой от самой структуры, чтобы операции можно было менять произвольно.
Важный момент — полиморфные операции. Потому что если нет динамического полиморфизма, то и визитор не нужен.
Здравствуйте, vdimas, Вы писали:
V>За это минус, ибо ни в какие ворота... Все "трюки", описанные в GOF были известны задолго до.
Приводи ссылку на первоисточник. Не забудь только, что речь не о трюках вообще, а о конкретном паттерне, названом конкретным термином.
V> GOF известен тем, что обобщил и что дал терминологию трюкам, ну и дохочиво, "на пальцах", разъяснил подходящие условия для применения упомянутых паттернов.
А речь здесь именно о терминологии, о том что называется словом "визитор". И для этого надо читать определения, а не заниматься фантазированием на тему. Считаешь что термин ввели не в банде? Возможно. Но тогда приводи первоисточник, будем смотреть что в нем написано.
V>Визитор — это трюк всегда известный под названием двойной диспетчеризации.
Ссылку на такое определение — в студию.
V> Словесная муть это, а не "другая точка зрения".
ПОка что словесная муть у тебя, потому что не подкреплена ни одной ссылкой.
V>ИМХО, это от непонимания концепции мультиметодов (частный случай которых в 2-х аргументах веселая четверка обозвала визитором, хотя суть паттерна "визитор" может быть расширена на любое кол-во аргументов, ибо это позволяют мультиметоды).
Это от того, что кое кто жонглирует терминами.
V>Посмотри на этот boost::variant, должно стать понятней, что имеют ввиду, когда говорят про "статического визитора" в С++.
Т.е. опять жонглирование терминами. Ссылку на определение "статического визитора" в студию.
V> В C# такого на генериках не получить, там потребуется именно некий интерфейс, требующий последующего переопределения, то бишь потребуется техника виртуальных ф-ий.
Виртуальные функции нужны не для интерфейса визитора, виртуальным (и объявленным в базовом классе) должен быть метод AcceptVisitor. Это принципиально. А сам визитор, конечно, же, может обходится и без виртуальных функций.
Здравствуйте, Ikemefula, Вы писали:
I>ФП-стиль это баззворд.
Под ФП-стилем обычно подразумевают ориентацию в дизайне на работу с функциональными объектами. Т.е. ср-ва для создания оных, и ожидание их же в кач-ве аргументов в публичном АПИ.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Скажу тебе по секрету: пишущие на C++ такой хренью не заморачиваются.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Head Ache, Вы писали:
HA>Почему, когда другие языки имитируют (обычно с потерей эффективности) фичи C++, такие как метапрограммирование, переопределение операторов, HA>объекты STL — это "круто", а С++ "слишком сложный"? HA>Черт возьми, ну не для всех он "слишком сложный"...
Я начинаю понимать лисперов ведь у них действительно "все украли"
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, Head Ache, Вы писали:
HA>>Почему, когда другие языки имитируют (обычно с потерей эффективности) фичи C++, такие как метапрограммирование, переопределение операторов, HA>>объекты STL — это "круто", а С++ "слишком сложный"? HA>>Черт возьми, ну не для всех он "слишком сложный"...
FR>Я начинаю понимать лисперов ведь у них действительно "все украли"
Здравствуйте, Ночной Смотрящий, Вы писали:
V>>Посмотри на этот boost::variant, должно стать понятней, что имеют ввиду, когда говорят про "статического визитора" в С++.
НС>Т.е. опять жонглирование терминами. Ссылку на определение "статического визитора" в студию.
Но (использовал не раз на деревянных структурах boost::variant) я никаких противоречий GOF'скому определению визитора
не увидел. По сути это и есть визитор.
Здравствуйте, vdimas, Вы писали:
I>>ФП-стиль это баззворд.
V>Под ФП-стилем обычно подразумевают ориентацию в дизайне на работу с функциональными объектами. Т.е. ср-ва для создания оных, и ожидание их же в кач-ве аргументов в публичном АПИ.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>>>Ну да цитату в студию. Лучше всего из банды, первоисточник все таки. I>>Там кривое изложение. НС>Давай источник с прямым.
Joshua Kerievsky
I>>В некоторых источниках визитор вообще сводится к двойной диспетчеризации.
НС>В языках с отсутствующей перегрузкой допустимо использование рукопашного разнесения по нужным методам. Да и в языках с онной иногда, для улучшения читаемости, от двойной диспетчеризации отказываются. Главное, это никак не меняет логику самого паттерна, всего лишь определяет, какую часть работы возьмет на себя компилятор.
Покажи мне решение для общего случая без двойной диспетчеризации.
I>>Виртуальный метод необязателен Утиной типизации может быть достаточно
НС>Что в лоб, что по лбу. Но пример то у тебя на шарпе, там никакой утиной типизации в статически типизированном контексте нет.
У меня пример на шарпе, но почему то только ты решил, будто я там какой то паттерн реализовал.
А там всего то тупой dfs чз лямбда-рекурсию, а визитор это вроде обфускации, что бы gandjustasа проверить.
Здравствуйте, gandjustas, Вы писали:
I>>P.S. А теперь попробуй решить вторую задачу, для которой я привел свое решение, — поиск всех роутов начиная с заданного вертекса. G>Нивопрос, выбирай
Итак, берем орграф вида:
1, 2, 3, 4
1 x x
2x x
3 x x
4x x
находим все роуты из 1, получаем — (1,2),(1,2,3),(1,2,3,4),(1,4),(1,4,3),(1,4,3,2)
Очевидно, ни одна твоя функция этот тест не проходит Ты в курсе, что bfs эту задачу не решает ?
I>>P.P.S. фунцыя в JS V8 походу порвёт твой _шедевр_ по перформансу. G>Нивопрос, приведи реальную задачу и тестовые данные.
А это реальная задача
Я упростил структуру модели, а сам алгоритм остался.
Тестовые данные — полносвязный граф из 100 элементов — это что бы кольца были в наличии, из него удалить рандомом примерно 80% связей — что бы алгоритм закончился в разумное время. Далее посчитать AllRoutes из одной вершины.
У меня есть оптимизирования версия, которая работает почти так же быстро как и С++ версия Хочешь сравнить всерьез — это сильно легко.
G>Я специально сделал поиск максимально ленивым, чтобы мог при желании ограничить перебор и даже не искать все пути на графе.
Ты специально сделал то, чего делать почти никогда и не нужно да еще и с ошибкой. Отсечения делаются при переборе, но немного не так, как тебе хочется.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>P.S. А теперь попробуй решить вторую задачу, для которой я привел свое решение, — поиск всех роутов начиная с заданного вертекса. G>>Нивопрос, выбирай
I>Итак, берем орграф вида: I>
I> 1, 2, 3, 4
I>1 x x
I>2x x
I>3 x x
I>4x x
I>
I>находим все роуты из 1, получаем — (1,2),(1,2,3),(1,2,3,4),(1,4),(1,4,3),(1,4,3,2)
Ты и не пытался объяснить что такое роуты
I>Очевидно, ни одна твоя функция этот тест не проходит Ты в курсе, что bfs эту задачу не решает ?
Я тебе уже говорил чтобы ты сформулировал решение в проверяемом виде.
Ты написал только это:
находит и возвращает все вертексы достижимые из заданного.
Я тебе привел два с половиной варианта, все они делают то что написано выше.
Так что не выкручивайся теперь.
I>>>P.P.S. фунцыя в JS V8 походу порвёт твой _шедевр_ по перформансу. G>>Нивопрос, приведи реальную задачу и тестовые данные. I>А это реальная задача
Нет, реальная задача имеет некоторый value для пользователя. В поиске всех роутов я value не вижу.
I>Тестовые данные — полносвязный граф из 100 элементов — это что бы кольца были в наличии, из него удалить рандомом примерно 80% связей — что бы алгоритм закончился в разумное время. Далее посчитать AllRoutes из одной вершины.
Ну так скинь сюда файл. На нем и будем забеги устраивать.
I>У меня есть оптимизирования версия, которая работает почти так же быстро как и С++ версия Хочешь сравнить всерьез — это сильно легко.
Нивопрос, я тоже могу ченить соптимизировать.
G>>Я специально сделал поиск максимально ленивым, чтобы мог при желании ограничить перебор и даже не искать все пути на графе.
I>Ты специально сделал то, чего делать почти никогда и не нужно
С чего ты взял?
I>да еще и с ошибкой. Отсечения делаются при переборе, но немного не так, как тебе хочется.
Так ты не удосужился написать как надо. А теперь строишь из себя самого умного.
Здравствуйте, Ночной Смотрящий, Вы писали:
V>>За это минус, ибо ни в какие ворота... Все "трюки", описанные в GOF были известны задолго до. V>> GOF известен тем, что обобщил и что дал терминологию трюкам, ну и дохочиво, "на пальцах", разъяснил подходящие условия для применения упомянутых паттернов.
НС>Приводи ссылку на первоисточник. Не забудь только, что речь не о трюках вообще, а о конкретном паттерне, названом конкретным термином.
Гугл по фразе "визитор двойная диспетчеризация" дает достаточно материала, ибо этот вопрос один из самых муссируемых относительно визитора. И на этом сайте неоднократно тоже.
НС>А речь здесь именно о терминологии, о том что называется словом "визитор". И для этого надо читать определения, а не заниматься фантазированием на тему. Считаешь что термин ввели не в банде? Возможно. Но тогда приводи первоисточник, будем смотреть что в нем написано.
Я вроде и написал, что банда дала термины.
Лишь обращаю внимание, что рассматриваемый трюк — частный случай более общего (и более полезного/важного) трюка, известного как множественная диспетчеризация. Поэтому уверен, что полезней понимать общую концепцию. Ибо если некая обезъянка "зазубрит" паттерн визитор без понимания происходящего, то расширить этот же паттерн на случай, когда у посетителя в методе visit(ConcreteObj) будет более одного аргумента, он уже не сможет. Упрется в бессилии. А ты пытаешься из нас делать этих обезянок, утверждая, что этот частный случай обладает некоей исключительностью перед более общим.
V>>Визитор — это трюк всегда известный под названием двойной диспетчеризации.
НС>Ссылку на такое определение — в студию.
Хорошая ссылка на гугл уже дана.
V>> Словесная муть это, а не "другая точка зрения".
НС>ПОка что словесная муть у тебя, потому что не подкреплена ни одной ссылкой.
Угу, по википедии шпарить мы можем, а вправо-влево по теме не можем... серьезней надо.
V>>ИМХО, это от непонимания концепции мультиметодов (частный случай которых в 2-х аргументах веселая четверка обозвала визитором, хотя суть паттерна "визитор" может быть расширена на любое кол-во аргументов, ибо это позволяют мультиметоды).
НС>Это от того, что кое кто жонглирует терминами.
Похоже, требуется для начала дать определение термину "жонглирование терминами". Потому как было четко сказано, что термин1 обозначает частный случай термина2. Где ты усмотрел жонглирование? Если не согласен с озвученным "обозначает частный случай", то аргументируй, в чем именно не согласен.
V>>Посмотри на этот boost::variant, должно стать понятней, что имеют ввиду, когда говорят про "статического визитора" в С++.
НС>Т.е. опять жонглирование терминами. Ссылку на определение "статического визитора" в студию.
Это сленг С++. Там много к чему известному добавляют приставку "статический" из-за особенностей имеющегося инструмента кодогенерации, позволяющего резко уменьшить частоту использования виртуальных ф-ий. Это способность дает еще один плюс (немного оффтоп), а именно: более низкая связанность кода ввиду отсутствия необходимости зависеть от некоего интерфейса с его уникальным контрактом. Т.е. шаблонные библиотеки не навязывают конкретики. Например, именно ввиду упомянутого возможна обобщенная библиотечная реализация паттерна визитор в C++, в то время как в дотнете библиотечная реализация этого паттерна принципиально невозможна.
НС>Виртуальные функции нужны не для интерфейса визитора, виртуальным (и объявленным в базовом классе) должен быть метод AcceptVisitor. Это принципиально.
Вообще-то, это принципиально для случая "внешнего" обхода, например через итераторы. Если же посещаемый "черный ящик" инкапсулирует логику обхода (а оно почти всегда так), то это не принципиально. В интернете есть разъяснения как первого варианта реализации визитора, так и второго. И пока не видел, чтобы кто-то считал один из вариантов более "визитёристым", чем другой. Фактически, ты первый, со своей принципиальностью.
НС>А сам визитор, конечно, же, может обходится и без виртуальных функций.
И как теперь с тобой вести дискуссию? По твоей логике здесь тоже должны быть принципиально виртуальные ф-ии, ведь в GOF описана ситуация, когда оба участника паттерна являются абстрактными. Совершенно не понимаю твоей логики, почему одну часть паттерна можно модифицировать, а другую нельзя.
ИМХО, ключевое во всей этой теме и корень взаимонепонимания — это рантайм полиморфизм, используемый при определении конкретного вызываемого метода посетителя. Только это и важно в паттерне и сохраняет его суть. Иначе не было бы смысла просить посещаемый объект об обратном вызове — можно было бы сразу вызывать нужный меод. Другое дело, что такой полиморфизм может быть реализован в некоторых языках без техники виртуальных ф-ий. Поэтому спор об обязательной технике реализации визитора на виртуальных ф-иях заведомо глуп, надо смотреть на суть вещей: есть некая задача, а вот к ней решение, отличающееся лишь техническими аспектами реализации (ввиду их наличия в некоем языке), но идентичное по логике происходящего. А иначе это не инженерия получается, а обезъяничество.
Здравствуйте, gandjustas, Вы писали:
I>>находим все роуты из 1, получаем — (1,2),(1,2,3),(1,2,3,4),(1,4),(1,4,3),(1,4,3,2) G>Ты и не пытался объяснить что такое роуты
Да очевидно — маршруты. В английском они называются path или route.
I>>Очевидно, ни одна твоя функция этот тест не проходит Ты в курсе, что bfs эту задачу не решает ? G>Я тебе уже говорил чтобы ты сформулировал решение в проверяемом виде.
G>Ты написал только это: G>
G>находит и возвращает все вертексы достижимые из заданного.
Это первая задача, с ней ты справился
G>Я тебе привел два с половиной варианта, все они делают то что написано выше. G>Так что не выкручивайся теперь.
первую задачу ты решил, а на второй — загруз
I>>А это реальная задача G>Нет, реальная задача имеет некоторый value для пользователя. В поиске всех роутов я value не вижу.
Ну вот смотри, нужно найти наилучшую схему доставки(снова упрощаю, что бы было понятно). Наилучшую — скажем, оптимальную по надежности, стоимости, длине, покрытию, количеству элементов в пути. Эту задачу дополняем целевой функцией, можно приближенной, фильтруем выход AllRoutes и, вуаля, наилучшая схема доставки найдена.
I>>Тестовые данные — полносвязный граф из 100 элементов — это что бы кольца были в наличии, из него удалить рандомом примерно 80% связей — что бы алгоритм закончился в разумное время. Далее посчитать AllRoutes из одной вершины. G>Ну так скинь сюда файл. На нем и будем забеги устраивать.
Тестовый файл есть только для полной структуры которая тебе без толку. Я же специально упростил структуру до предела
I>>У меня есть оптимизирования версия, которая работает почти так же быстро как и С++ версия Хочешь сравнить всерьез — это сильно легко. G>Нивопрос, я тоже могу ченить соптимизировать.
Конечно, linq тебе придется выбросить и ты придешь почти к той же форме, которую я тебе подкинул И в любом случае js версия короче и понятнее.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>находим все роуты из 1, получаем — (1,2),(1,2,3),(1,2,3,4),(1,4),(1,4,3),(1,4,3,2) G>>Ты и не пытался объяснить что такое роуты I>Да очевидно — маршруты. В английском они называются path или route.
Не прячь знания за терминологией. Объясни по-русски что это такое.
I>>>Очевидно, ни одна твоя функция этот тест не проходит Ты в курсе, что bfs эту задачу не решает ? G>>Я тебе уже говорил чтобы ты сформулировал решение в проверяемом виде.
G>>Ты написал только это: G>>
G>>находит и возвращает все вертексы достижимые из заданного.
I>Это первая задача, с ней ты справился
Вау...
G>>Я тебе привел два с половиной варианта, все они делают то что написано выше. G>>Так что не выкручивайся теперь. I>первую задачу ты решил, а на второй — загруз
Так ты её не сформулировал
I>>>А это реальная задача G>>Нет, реальная задача имеет некоторый value для пользователя. В поиске всех роутов я value не вижу.
I>Ну вот смотри, нужно найти наилучшую схему доставки(снова упрощаю, что бы было понятно). Наилучшую — скажем, оптимальную по надежности, стоимости, длине, покрытию, количеству элементов в пути. Эту задачу дополняем целевой функцией, можно приближенной, фильтруем выход AllRoutes и, вуаля, наилучшая схема доставки найдена.
Ок
1)Граф связей между точками
2)Многозначная функция весов между узлами графа
3)Целевая функция, которая берет множество значений весов и возвращает число
4)Нужно найти такую такую последовательность точек между заданными начальной и конечной точкой, чтобы функция была минимальна
public static IEnumerable<IEnumerable<T>> DepthFirst<T>(T item, Func<T, IEnumerable<T>> adjacentNodes, Func<IStack<T>, bool> predicate)
{
return DepthFirstImpl(ImmutableStack.Create(item), adjacentNodes, predicate).MemoizeAll();
}
private static IEnumerable<IStack<T>> DepthFirstImpl<T>(IStack<T> path, Func<T, IEnumerable<T>> adjacentNodes, Func<IStack<T>, bool> predicate)
{
return (from n in adjacentNodes(path.Top)
let pp = path.Push(n)
where predicate(pp)//Вот тут самое интересное, если predicate возвращает false, то продолжение перебора по этому пути не идетfrom p in DepthFirstImpl(pp, adjacentNodes, predicate)
select p)
.StartWith(path);
}
public static IEnumerable<T> ShortestPath<T>(T from, T to, Func<T, IEnumerable<T>> adjacentNodes, Func<IEnumerable<T>, double> weight)
{
var minWeights = new Dictionary<T, double>();
var minWeight = double.MaxValue;
IEnumerable<T> minPath = null;
DepthFirst(from, adjacentNodes, path =>
{
var w = weight(path);
double value = 0;
if (w < minWeight && (!minWeights.TryGetValue(path.Top, out value) || w < value))
{
minWeights[path.Top] = w;
if (to.Equals(path.Top))
{
minPath = path;
minWeight = w;
}
return true;
}
return false;
});
return minPath;
}
При этом с небольшими изменениями можно распараллелить этот код.
I>>>Тестовые данные — полносвязный граф из 100 элементов — это что бы кольца были в наличии, из него удалить рандомом примерно 80% связей — что бы алгоритм закончился в разумное время. Далее посчитать AllRoutes из одной вершины. G>>Ну так скинь сюда файл. На нем и будем забеги устраивать.
I>Тестовый файл есть только для полной структуры которая тебе без толку. Я же специально упростил структуру до предела
Для забегов нужны данные, а не "структура"
I>>>У меня есть оптимизирования версия, которая работает почти так же быстро как и С++ версия Хочешь сравнить всерьез — это сильно легко. G>>Нивопрос, я тоже могу ченить соптимизировать.
I>Конечно, linq тебе придется выбросить и ты придешь почти к той же форме, которую я тебе подкинул И в любом случае js версия короче и понятнее.
Так покажи наконец js версию.
Здравствуйте, Ikemefula, Вы писали:
V>>Под ФП-стилем обычно подразумевают ориентацию в дизайне на работу с функциональными объектами. Т.е. ср-ва для создания оных, и ожидание их же в кач-ве аргументов в публичном АПИ.
I>А что такое функциональный объект ?
Здравствуйте, gandjustas, Вы писали:
I>>Да очевидно — маршруты. В английском они называются path или route. G> G>Не прячь знания за терминологией. Объясни по-русски что это такое.
См. определение для маршрута хотя бы в википедии с той разницей что в нашей задаче дуги вырожденные и маршрут сводится к последовательности узлов, для простоты — орграф не является мультиграфом.
I>>Ну вот смотри, нужно найти наилучшую схему доставки(снова упрощаю, что бы было понятно). Наилучшую — скажем, оптимальную по надежности, стоимости, длине, покрытию, количеству элементов в пути. Эту задачу дополняем целевой функцией, можно приближенной, фильтруем выход AllRoutes и, вуаля, наилучшая схема доставки найдена. G>Ок G>1)Граф связей между точками
есть набор точек и набор соединений между точками. для простоты считаем, что связи не имеют никаких весов и нас в этой задаче не интересуют, т.е. это упрощение
G>2)Многозначная функция весов между узлами графа
У узла есть некоторые характеристики, так же характеристики есть у пути, есть у покрытия(набор путей которые обеспечивают достижимость всех узлов в подграфе).
G>3)Целевая функция, которая берет множество значений весов и возвращает число
целевая функция принимает покрытие и возвращает число, в простом виде это можно оформить суммой значений
G>4)Нужно найти такую такую последовательность точек между заданными начальной и конечной точкой, чтобы функция была минимальна
где ты взял конечную точку ? Я про это ничего не говорил. Ищется схема доставки, а не один путь доставки. В качестве объяснения — один склад товара на страну и одноразовые курьеры мотаются от склада к клиентам.
В задаче нужно найти покрытие для которого функция минимальна
Очевидно — задача слишком сложная, что бы мерять её ради форумной баталии. Потому я предложил тебе упрощенный случай — только первую фазу, поиск всех маршрутов. G>При этом с небольшими изменениями можно распараллелить этот код.
Код я скипнул, потому что ты поторопился с решением. В этой функции нельзя заранее отсекать варианты Потому еще раз — лучше ограничиться только поиском всех маршрутов — первая фаза.
Во второй фазе алгоритма придется искать каркас алгоритмом, скажем, Крускала, т.к. в граф путей уже неориентированый, что даёт линейную сложность для реальных данных.
I>>Тестовый файл есть только для полной структуры которая тебе без толку. Я же специально упростил структуру до предела G>Для забегов нужны данные, а не "структура"
Я вроде описал, как можно сгенерировать эти данные, строишь т.н. турнир, см. вики про орграфы, удаляешь 80-90% связей.
I>>Конечно, linq тебе придется выбросить и ты придешь почти к той же форме, которую я тебе подкинул И в любом случае js версия короче и понятнее. G>Так покажи наконец js версию.
Тю, бестиповость и отсутствие необходмости предварительного объявления переменных сэкономили несколько строк на выхолощенном примере. Ты припиши туда хотя бы возможность подписки на события изменения состояний.
Определения Callback, Signal и ServerState были скопированы из ProtocolController.h для полноты картины. В нем реакция на события и генерирование входных сигналов для автомата.
Fsm.h сделан однократно много лет назад и постоянно используется.
В общем, возможность переопределения операторов позволяют сделать синтаксис более-менее декларативным в C++.
Здравствуйте, vdimas, Вы писали:
V>>>Под ФП-стилем обычно подразумевают ориентацию в дизайне на работу с функциональными объектами. Т.е. ср-ва для создания оных, и ожидание их же в кач-ве аргументов в публичном АПИ.
I>>А что такое функциональный объект ?
V>Это аналог первоклассной функции в ФП языках.
Т.е. это нечто, что выглядит как функция, но ею не является и по этой причине вводит в заблуждение + затрудняет понимание — это как раз про СТЛ и БУСТ.
Здравствуйте, vdimas, Вы писали:
V>Вот тебе реальный "боевой пример":
... V>В общем, возможность переопределения операторов позволяют сделать синтаксис более-менее декларативным в C++.
В декларативном стиле и ФП-стиле это чуток разные вещи. С декларативным я согласен. С ФП — категорически нет.
Здравствуйте, Ikemefula, Вы писали:
I>В задаче нужно найти покрытие для которого функция минимальна I>Очевидно — задача слишком сложная, что бы мерять её ради форумной баталии. Потому я предложил тебе упрощенный случай — только первую фазу, поиск всех маршрутов.
Ну я даже не удивлен что ты снова поменял условия задачи.
G>>При этом с небольшими изменениями можно распараллелить этот код.
I>Код я скипнул, потому что ты поторопился с решением. В этой функции нельзя заранее отсекать варианты Потому еще раз — лучше ограничиться только поиском всех маршрутов — первая фаза.
Это как раз прекрасно делает ленивый вариант обхода.
I>Во второй фазе алгоритма придется искать каркас алгоритмом, скажем, Крускала, т.к. в граф путей уже неориентированый, что даёт линейную сложность для реальных данных.
Честно говоря уже надоело.
Ты не привел ни одного обоснования своим словам, ни про размер кода, ни про быстродействие, ни про визиторы, постоянно пытаешься увильнуть.
Кстати с чего все началось: для обхода графов вполне достаточно Linq и комбинаторов.
Здравствуйте, Ikemefula, Вы писали:
I>>>Там кривое изложение. НС>>Давай источник с прямым.
I>Joshua Kerievsky
Нет, ты определение давай. Или предлагаешь мне все сочинения этого автора перечитать?
I>Покажи мне решение для общего случая без двойной диспетчеризации.
Что значит "для общего случая" и где я такое обещал?
I>а визитор это вроде обфускации, что бы gandjustasа проверить.
Здравствуйте, vdimas, Вы писали:
НС>>Приводи ссылку на первоисточник. Не забудь только, что речь не о трюках вообще, а о конкретном паттерне, названом конкретным термином.
V>Гугл по фразе "визитор двойная диспетчеризация" дает достаточно материала, ибо этот вопрос один из самых муссируемых относительно визитора. И на этом сайте неоднократно тоже.
Это уход от вопроса.
V>Лишь обращаю внимание, что рассматриваемый трюк — частный случай более общего
Зачем?
V> Поэтому уверен, что полезней понимать общую концепцию.
Возможно. Но к чему ты это?
V>А ты пытаешься из нас делать этих обезянок, утверждая, что этот частный случай обладает некоей исключительностью перед более общим.
Ссылку в студию.
НС>>Ссылку на такое определение — в студию.
V>Хорошая ссылка на гугл уже дана.
Ссылка в гугль эквивалентна посыланию на три или пять букв.
НС>>ПОка что словесная муть у тебя, потому что не подкреплена ни одной ссылкой.
V>Угу, по википедии шпарить мы можем, а вправо-влево по теме не можем... серьезней надо.
Тем не менее выделенное — чистая правда.
НС>>Это от того, что кое кто жонглирует терминами.
V>Похоже, требуется для начала дать определение термину "жонглирование терминами".
Какая красота.
V>Например, именно ввиду упомянутого возможна обобщенная библиотечная реализация паттерна визитор в C++, в то время как в дотнете библиотечная реализация этого паттерна принципиально невозможна.
Обобщенная — наверное нет, хотя без внимательного рассмотрения вопроса я бы не стал это с абсолютной уверенностью утверждать. А вот частный случай вполне возможен. И при рукопашной реализации частного случая визитор визитором быть не перестает, не так ли? Но ты то изначально утверждал несколько другое:
НС>Это не паттерн Visitor, а какая то фигня. Паттерн используется, когда нужна диспетчеризация по типам с общим корнем.
На статическом полиморфизме визитор тоже прекрасно работает, например в С++.
Прошу обратить внимание, чему именно ты противопоставляешь статику.
V>Вообще-то, это принципиально для случая "внешнего" обхода
Ять! Визитор предназначен для внешнего "подключения" алгоритма. По определению! Слово "обход" у тебя, кстати, очень показательно.
V>, например через итераторы. Если же посещаемый "черный ящик" инкапсулирует логику обхода (а оно почти всегда так), то это не принципиально. В интернете есть разъяснения как первого варианта реализации визитора, так и второго. И пока не видел, чтобы кто-то считал один из вариантов более "визитёристым", чем другой. Фактически, ты первый, со своей принципиальностью.
Визитор это не обход, это диспетчеризация. Обход, конечно, иногда может быть встроен (далеко не всегда!), но это конкретная реализация, комбинирующая несколько вещей. В паттерне никакого обхода нет.
V>И как теперь с тобой вести дискуссию?
Без софистики, подтасовок и упорном нежелании ссылаться на реальные определения.
V> По твоей логике здесь тоже должны быть принципиально виртуальные ф-ии
Это по твоей логике.
V>, ведь в GOF описана ситуация, когда оба участника паттерна являются абстрактными.
В GoF есть еще и определение паттерна. Перечитай.
V> Совершенно не понимаю твоей логики, почему одну часть паттерна можно модифицировать, а другую нельзя.
Модифицировать можно что угодно. Но если после этого определение (не пример, а именно определение) перестает подходить, то оно перестает быть визитором. Все очень просто.
V>ИМХО, ключевое во всей этой теме и корень взаимонепонимания — это рантайм полиморфизм, используемый при определении конкретного вызываемого метода посетителя.
Это не корень взаимонепонимания, а кое кто не потрудился понять, на что же он все таки отвечал.
V>Другое дело, что такой полиморфизм может быть реализован в некоторых языках без техники виртуальных ф-ий.
Возможно. Но это не может быть реализовано статически. На статику можно заменить реализацию визитора, но нельзя сделать статическим сам механизм диспетчеризации. Как нельзя сделать полностью статическими мультиметоды или PM по АлгТД.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Возможно. Но это не может быть реализовано статически. На статику можно заменить реализацию визитора, но нельзя сделать статическим сам механизм диспетчеризации. Как нельзя сделать полностью статическими мультиметоды или PM по АлгТД.
Если взять boost::variant там динамическая диспетчеризация конечно присутствует, правда виртуальных вызовов нет,
есть банальный switch в потрохах. Но это же не мешает сделать подобный visitor полностью отрабатывающий в compile
time в том же C++ или проще в D, понятно что в рантайме будет доступен только результат его работы. В том же D
наверняка можно сделать код который будет одинаков что в рантайме что в компилтайме.
По моему все эти разделения весьма зыбки и шатки, и не думаю что именно динамическая диспетчеризация позволит
отличить визитор от невизитора.
Здравствуйте, DelphiGuru, Вы писали:
DG>После недели детального изучения исходников STL я пришел к выводу, что ее можно реализовать при помощи чистого ООП. Что думают пишущие на Си++ об этом
Так так, сейчас я сделаю выброс на вентилятор =)
И так, Делфи это не только Борланд или кодегеар, это не только 500$ за минимальную лицензию, это не только Windows зависимость, но это также opensource компилятор FreePascal под win, mac, linux, iphone и другие платформы, это также opensoucre IDE Lazarus со своей системой библиотек GUI, которая обеспечивает кроссплатформенность без свистоплясок. Нужен тебе gui на основе GTK, QT, WinAPI и др. не проблема, библиотека LCL настолько уникальна, что позволяет без изменения кода легко переходит от GTK к QT и т.п. Ну что соснули? Пока вы тут пишите на Qt Creator'e хвастаясь кроссплатформенностью, Lazarus уделал вас по полной, он не зависит от какого-то тул-кита. А FreePascal уделал си++ по скорости компиляции, по организации модулей. Хвастаетесь крутыми фишками в ООП си++? Многие эти фишки красиво реализованы в freepascal. Что еще говорить о встроенном сборщике мусора для типа String в freepascal и delphi? Конечно сейчас начнется кидание библиотеками.
Freepascal умеет статически линковать объектные файлы gcc, любой код написанный на gcc может быть легко присоединен статически к приложениям на фрипаскаль.
СИ++ это настоящий костыль над костылем, Страуструп соответствует своей фамилии, потому что его книги ужасны, по ним становится понятно, что у самого автора в голове творится самый настоящий бардак, такой же бардак творится и в стандарте си++. СИ жив только благодаря linux'у, да и потому что альтернатив компилируемых языков можно сосчитать по пальцам, что кроме freepascal может придти в голову? такое же кроссплатформенное и развивающеся?
Поэтому, чтобы у всех был выбор, и чтобы потом мы не потонули в том говне всяких JIT, байт компиляторов и тп., надо хранить и развивать компилируемые языки как можно лучше. Поэтому си++-ники должны радоваться, что их языку и компилятору есть альтернатива. Java, C# и т.п., это не альтернатива, это во-первых продукты корпораций, во-вторых — это некомпилируемые языки, они тянут за собой кучу зависимостей.
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, dim-s, Вы писали:
DS>>Так так, сейчас я сделаю выброс на вентилятор =)
FR>Вяловато, да и опоздал лет на десять
Без причины я не выбрасываю на вентилятор ничего =) Десять лет назад я не программировал, поэтому радуюсь что 10 лет назад нашлись люди, которые не потеряли веру в этот язык и написали компилятор, а потом и среду для него. Делфи как язык с платным и закрытым компилятором не может существовать в современном мире.
Здравствуйте, dim-s, Вы писали:
d> И так, Делфи это не только Борланд или кодегеар, это не только 500$ за минимальную лицензию, это не только Windows зависимость, но это также opensource компилятор FreePascal под win, mac, linux, iphone и другие платформы, это также opensoucre IDE Lazarus со своей системой библиотек GUI, которая обеспечивает кроссплатформенность без свистоплясок.
У дельфей выходит (на след. неделе, кажется) стартер едишн за $200. Следующая версия (после XE) обещает кроссплатформу и 64 бита. FPC действительно неплох, но лично мне для работы с ним не хватает поддержки advanced records и nested types, которые уже появились в ветке 2.5.1, но пока официально не релизнуты.
Здравствуйте, Ikemefula, Вы писали:
V>>Это аналог первоклассной функции в ФП языках.
I>Т.е. это нечто, что выглядит как функция, но ею не является и по этой причине вводит в заблуждение + затрудняет понимание — это как раз про СТЛ и БУСТ.
Что значит "ею не является"? В STL и boost во всех местах, где можно подать как параметр обычную ф-ию, можно подать и функтор (функциональный объект в терминах С++).
И поясни, плиз, что именно вводит в заблуждение, и в чем состоит само заблуждение?
--------------------------
Я было хотел начать пояснять прямо тут, но гугл по фразе "функтор С++" вываливает более доходчивую инфу.
Здравствуйте, hattab, Вы писали:
H>Здравствуйте, dim-s, Вы писали:
d>>Делфи как язык с платным и закрытым компилятором не может существовать в современном мире.
H>Реальность с тобою не согласна Все же качество FPC и Lazarus не дотягивает до дельфей, что впрочем не удивительно.
Бесплатность, открытость, кроссплатформенность, 64 битные версии с лихвой окупают эти недостатки. Конечно не так удобно для тех, кто кидает компоненты и пишет код только в событиях =). Отладка в последних версиях лазаруса стала вполне хорошей.
Здравствуйте, hattab, Вы писали:
H>Здравствуйте, dim-s, Вы писали:
d>> И так, Делфи это не только Борланд или кодегеар, это не только 500$ за минимальную лицензию, это не только Windows зависимость, но это также opensource компилятор FreePascal под win, mac, linux, iphone и другие платформы, это также opensoucre IDE Lazarus со своей системой библиотек GUI, которая обеспечивает кроссплатформенность без свистоплясок.
H>У дельфей выходит (на след. неделе, кажется) стартер едишн за $200. Следующая версия (после XE) обещает кроссплатформу и 64 бита. FPC действительно неплох, но лично мне для работы с ним не хватает поддержки advanced records и nested types, которые уже появились в ветке 2.5.1, но пока официально не релизнуты.
На мой взгляд, даже когда делфи сделают кроссплатформенной она все равно не сможет сразу догнать в этом плане лазаруса и freepascal, потому что под lazarus написано огромное количество кросс гуи компонентов. А цена 200$, интересно, можно ли на этой лицензии делать комерческие продукты? И кстати я думаю цена кроссплатформенной делфи и делфи только под windows будут ох как отличатся, достаточно глянуть на QT creator.
А у fpc есть advanced records не только в 2.5.1, но и в 2.4.2 по-моему. Может быть они там ограниченные, но например переопределять операторы можно. Что же говорить о вложенных типах? Мне кажется пора бы вспомнить Вирта, и все эти возможности уже есть, просто подход с другого места, а суть все равно одна. Для чего собственно объекты, я боюсь recordы превратятся в объекты аля стиля object pascal.
Здравствуйте, dim-s, Вы писали:
d> Бесплатность, открытость, кроссплатформенность, 64 битные версии с лихвой окупают эти недостатки.
Да я согласен, кто же спорит, но код генерится тормозной (не в доску конечно, но все же). У дельфи компилятор далек от идеала, а у FPC выходит еще дальше.
d> Конечно не так удобно для тех, кто кидает компоненты и пишет код только в событиях =). Отладка в последних версиях лазаруса стала вполне хорошей.
Да я вообще не о дизайнере говорю (как по мне так в LCL совсем даже не плохо сделаны привязки контролов, можно вообще без layout'ов обходиться, в VCL такого нет), я говорю о качестве
Я и сам порадуюсь, когда выйдет 2.5.1 и я смогу свой проект скомпилить под Линукс, даже если к тому времени уже выйдет кроссплатформенная дельфя
Здравствуйте, dim-s, Вы писали:
d> H>У дельфей выходит (на след. неделе, кажется) стартер едишн за $200. Следующая версия (после XE) обещает кроссплатформу и 64 бита. FPC действительно неплох, но лично мне для работы с ним не хватает поддержки advanced records и nested types, которые уже появились в ветке 2.5.1, но пока официально не релизнуты.
d> На мой взгляд, даже когда делфи сделают кроссплатформенной она все равно не сможет сразу догнать в этом плане лазаруса и freepascal, потому что под lazarus написано огромное количество кросс гуи компонентов.
Ну так и Москва не сразу строилась. Главное, что будет официальная поддержка кроссплатформы. Под тот же CLX (кроссплатформенный аналог VCL в Kylix на основе Qt) компоненты появлялись достаточно быстро, некоторые до сих пор декларируют совместимость с CLX.
d> А цена 200$, интересно, можно ли на этой лицензии делать комерческие продукты? И кстати я думаю цена кроссплатформенной делфи и делфи только под windows будут ох как отличатся, достаточно глянуть на QT creator.
Да, разрабатывать коммерческий софт на стартере можно, но там ограничение на доходность компании (впрочем это не проблема, ведь как только софт начнет приносить прибыль можно и до проф. апгрейдиться)
d> А у fpc есть advanced records не только в 2.5.1, но и в 2.4.2 по-моему. Может быть они там ограниченные, но например переопределять операторы можно.
Нету adv.records в 2.4.2 (они даже в 2.5.1 еще ограничены, не имеют конструкторов) Перегрузка операторов это еще не все
d> Что же говорить о вложенных типах? Мне кажется пора бы вспомнить Вирта, и все эти возможности уже есть, просто подход с другого места, а суть все равно одна.
Вложенные типы нужны для улучшения инкапсуляции, это очевидно, как по мне Самый банальный пример это TList и TList.TEnumerator вместо TList и TListEnumerator.
d> Для чего собственно объекты, я боюсь recordы превратятся в объекты аля стиля object pascal.
Object уже давно объявлены obsolete и поддерживаются только для обратной совместимости. А adv.records удобно использовать вместо обычных классов/объектов в тех случаях где делать инстанционирование объектов неудобно (скажем, мелкие объекты типа TStopwatch).
Здравствуйте, hattab, Вы писали:
H>Здравствуйте, dim-s, Вы писали:
d>> Бесплатность, открытость, кроссплатформенность, 64 битные версии с лихвой окупают эти недостатки.
H>Да я согласен, кто же спорит, но код генерится тормозной (не в доску конечно, но все же). У дельфи компилятор далек от идеала, а у FPC выходит еще дальше.
d>> Конечно не так удобно для тех, кто кидает компоненты и пишет код только в событиях =). Отладка в последних версиях лазаруса стала вполне хорошей.
H>Да я вообще не о дизайнере говорю (как по мне так в LCL совсем даже не плохо сделаны привязки контролов, можно вообще без layout'ов обходиться, в VCL такого нет), я говорю о качестве
H>Я и сам порадуюсь, когда выйдет 2.5.1 и я смогу свой проект скомпилить под Линукс, даже если к тому времени уже выйдет кроссплатформенная дельфя
Ну на счет тормознутости генерируемого asm кода fpc я бы не сказал, максимум он отстает на 20%. Знаю что там тормознутый SetLength например, но можно же использовать функции для выделения памяти, что и сделано в реализации TList и т.п. Например TList в лазарусе быстрее чем в делфи, а юникод в Гуи был с самого начала, но там как-то так сделали, что нет проблем с ansistring и юникодным gui. У меня были некоторые тесты, где fpc выигрывал у делфи в 4-5 раз, а было и наоборот.
Здравствуйте, hattab, Вы писали:
d>> А у fpc есть advanced records не только в 2.5.1, но и в 2.4.2 по-моему. Может быть они там ограниченные, но например переопределять операторы можно.
H>Нету adv.records в 2.4.2 (они даже в 2.5.1 еще ограничены, не имеют конструкторов) Перегрузка операторов это еще не все
Ну а что мешает написать функцию record'a которая будет возвращать созданный объект в куче. И тот же Free =).
Здравствуйте, dim-s, Вы писали:
d> H>Нету adv.records в 2.4.2 (они даже в 2.5.1 еще ограничены, не имеют конструкторов) Перегрузка операторов это еще не все
d> Ну а что мешает написать функцию record'a которая будет возвращать созданный объект в куче. И тот же Free =).
Конструкторы записей размещают их на стеке, а не в куче. Впрочем, есть надежда, что конструкторы в 2.5.x таки появятся.
Здравствуйте, dim-s, Вы писали:
d> Ну на счет тормознутости генерируемого asm кода fpc я бы не сказал, максимум он отстает на 20%.
Я как то тестировал на своих задачах — ~30%. С вариантами вообще 40%. Можешь сам проверить:
v : Variant;
i : Integer;
v := 1;
for i := 1 to 100000000 do
v := v + v / v;
Delphi 2010 — 9 сек. FPC 2.5.1 — 15 сек.
d> Знаю что там тормознутый SetLength например, но можно же использовать функции для выделения памяти, что и сделано в реализации TList и т.п. Например TList в лазарусе быстрее чем в делфи
С чего бы TList'у в FPC быть быстрее дельфийского, когда они реализованы одинаково?
d>, а юникод в Гуи был с самого начала, но там как-то так сделали, что нет проблем с ansistring и юникодным gui.
Ну в гуе у них Linux way Сделали UTF-8 в ансистроках.
d> У меня были некоторые тесты, где fpc выигрывал у делфи в 4-5 раз, а было и наоборот.
Как говорится, тесты в студию! Самому интересно посмотреть.
По своей сути паттерн посетитель позволяет, не изменяя классы, добавлять в них новые операции. Достигает он этого с помощью приема, называемого двойной диспетчеризацией. Данная техника хорошо известна.
Дизайн шаблона, который решает проблемы такого рода, называется "визитер" (это последний дизайн шаблона в книге "Design Patterns"), и он строится на схеме двойной диспетчеризации, показанной в предыдущем разделе.
Широко распространён пример с обходом древовидной структуры, где для каждого типа узла вызываются определённые операции. Чтобы избежать в коде уродливых switch/case в языках с передачей сообщений (C++/Java/SmallTalk/C#/e.t.c.) используют паттерн "Visitor", в реализации которого используется двойная диспетчеризация.
Ну и сама книжка GOF, разумеется. В ней об отношении этого паттерна и способа двойной диспетчеризации рассказано подробно. Другое дело, что авторы считают тему мультиметодов сложноватой, а книга изначально расчитана на новичков, поэтому и качество подачи материала соответствующее, и термины подобраны "приземленные".
НС>Ссылка в гугль эквивалентна посыланию на три или пять букв.
Ну, требование ссылок на легкодоступную информацию в приличном обществе, в свою очередь, эквивалентна автоматическому самопосыланию.
V>>Например, именно ввиду упомянутого возможна обобщенная библиотечная реализация паттерна визитор в C++, в то время как в дотнете библиотечная реализация этого паттерна принципиально невозможна.
НС>Обобщенная — наверное нет, хотя без внимательного рассмотрения вопроса я бы не стал это с абсолютной уверенностью утверждать.
Рассматривали, поверь. Выходит только на рефлексии (через рефлексию вообще можно что угодно, понятное дело, со всеми её тормозами), или через кодогенерацию, что уже не тянет на библиотечность.
НС>А вот частный случай вполне возможен. И при рукопашной реализации частного случая визитор визитором быть не перестает, не так ли?
Частный случай не может попасть в библиотеку, ибо кол-во и сигнатура методов accept() у визитора зависит от конкретного семейства обслуживаемых типов. Т.е. обслужить заведомо неизвестное семейство типов такая реализация не в состоянии.
НС>Но ты то изначально утверждал несколько другое: НС>
НС>>Это не паттерн Visitor, а какая то фигня. Паттерн используется, когда нужна диспетчеризация по типам с общим корнем.
НС>На статическом полиморфизме визитор тоже прекрасно работает, например в С++.
НС>Прошу обратить внимание, чему именно ты противопоставляешь статику.
Коллега... А ты точно нам коллега? А то меня уже не в первый раз терзают смутные сомнения... Особенно когда ты оперируешь MSDN-ом и википедией вместо своего мнения.
Понимаешь, статика может быть противопоставлена в том контексте только "общему корню". Уверен, любому коллеге даже не хватит воображения противопоставить статику в том контексте чему-либо другому.
V>>Вообще-то, это принципиально для случая "внешнего" обхода
НС>Ять! Визитор предназначен для внешнего "подключения" алгоритма. По определению! Слово "обход" у тебя, кстати, очень показательно.
Нет такого определения и такого предназначения. В первоисточнике сказано:
Ответственность за обход можно возложить либо на саму структуру объектов, либо на посетителя либо на отдельный объект-итератор (см. паттерн итератор).
Чаще всего структура объектов отвечает за обход. Коллекция просто обходит все свои элементы, вызывая для каждого операцию Accept. Составной объект обычно обходит самого себя, «заставляя» операцию Accept посетить потомков текущего элемента и рекурсивно вызвать Accept для каждого из них.
Вот на это я обратил внимание, говоря, что требование посещаемым объектам быть виртуальными — непринципиально, и зависит от сценария обхода. Поэтому ты серьезно ошибся в утверждении насчет обязательности посещаемому быть виртуальным. Ну а насчет необязательности самого визитора быть виртуальными ты уже дважды согласился, и тут ты прав, хотя это тоже "немного противоречит" описанию паттерна. Но там же лажа полная местами: "Для полной независимости посетители имеют отдельную от обслуживаемых структур иерархию". Это что-то вроде телепатического ООП-анализа на расстоянии или как этот грубый косяк назвать?
Конкретно в паттерне они сразу ввели абстрактного посетителя, чтобы можно было подавать разные объекты посетителей для обхода структуры. Но ведь это вообще ортогонально поставленной ими же проблематике и является overdesign для этого паттерна. Если такое требование возникает в конкретных случаях, то для эти случаев они уже давали соотв. паттерны выше в той же самой книге. В общем, на лицо немного сумбур и недостаточный анализ собственных же приводимых примеров. Простить их можно только в том случае, если вспомнить, на какую аудиторию расчитана данная книга: т.е. это что-то из области "полезных советов для начинающих ООП-адептов".
Так что вопрос остается в силе:
Совершенно не понимаю твоей логики, почему одну часть паттерна можно модифицировать, а другую нельзя.
В общем, в решении подразумевается отсутствие навыков инкапсуляции, и отсюда ошибочное требование абстрактного посетителя. Сермяжная правда в том, что эта абстракция в реальной жизни нужна в менее половины случаев, потому как визитор по большей части используется не в AST, а в тех случаях, когда некие близкие по характеру операции в множества однородных объектов было решено вынести в некий другой объект, отвечающий за такие близкие по характеру операции. Т.е. чаще всего ровно один тип посетителя, связанный с данным семейством типов, потому и не требуется для него абстрактный интерфейс. Осталось сделать еще один маленький шажок и понять, что это семейство не обязано быть "из одного корня". Вот конкретно на что было изначальное возражение.
НС>Визитор это не обход, это диспетчеризация.
Мы что, уже успели поменять местами, или ты решил начать маневры?
Единичный вызов визитора действительно и есть банальная диспетчеризация мультиметода, о чем я и говорю. Заменив этот единственный вызов на понятие "обход", адепты свидетелей GOF с пеной у рта доказывают, что визитор не есть двойная диспетчеризация, а лишь испопльзует её как инструмент (да и авторы явно об этом пишут в GOF). Более разумные авторы пишут, что в языках с множественной диспетчеризацией паттерн визитор не нужен по определению. Я лишь добавлю, что если эта же возможность достигается библиотечной двойной диспетчеризацией, то паттерн тоже не нужен. Вернее, ср-ва, ради которых паттерн строился, по прежнему нужны, но в выделенном виде этот паттерн не нужен, ибо полностью дублируется механизмом множественной диспетчеризации. Всю цепочку рассуждений на этот раз отследил? Просто как бэ 3-й раз одно и то же разынми словами талдычить... мы же в общественном месте... это ты паранджу натянул, а я человек публичный...
НС>Обход, конечно, иногда может быть встроен (далеко не всегда!), но это конкретная реализация, комбинирующая несколько вещей. В паттерне никакого обхода нет.
Похоже, ты наконец прошелся по ссылкам из поисковика, похвально. Еще чуть-чуть и ты ухватишь изначальную проблематику паттерна, и спор утихнет сам собой.
Правда, выглядит так, что разыне части этого поста ты писал, обладая разной информацией, иначе к чему твое "ять", если обход не принципиален? Так он есть или нет? Мы обходим элементы коллекции или инкапсулированные поля известного типа? Так нужен общий корень или не нужен?
НС>Без софистики, подтасовок и упорном нежелании ссылаться на реальные определения.
Беда в том, что не все определения формальны. Например, "множественная диспетчеризация" имеет формальное определение, а "визитор" — нет, там воды на несколько страниц. Отсюда бодание на ровном месте. Именно поэтому я попросил поделиться, что есть на твой взгляд "жонглирование терминами" в данном контексте. Жаль, что ты не понял намека, и что-то там оффтопное буркнул в ответ.
V>> По твоей логике здесь тоже должны быть принципиально виртуальные ф-ии
НС>Это по твоей логике.
Это кое-кто уже банально упускает нить беседы. Это ведь ты требуешь следовать букве паттерна, а я пытаюсь возражать, говоря, что для сохранения работоспособности паттерна это необязательно.
НС>В GoF есть еще и определение паттерна. Перечитай.
Вот именно. Перечитай. Там достаточно страниц описания на каждый паттерн, насколько я помню, так что давай копируй сюда то, что ты считаешь формальным определением. ИМХО, описание решения никак не может претендовать ни на какое формальное определение. И уж тем более то описание не в состоянии обособить этот паттерн от формального определения множественной диспетчеризации. Так что наши ваших бьют.
НС>Модифицировать можно что угодно. Но если после этого определение (не пример, а именно определение) перестает подходить, то оно перестает быть визитором. Все очень просто.
Повторю, не вижу формального определения паттерна. Вижу лишь постановку задачи, и способ ее решения на двойной диспетчеризации.
НС>Это не корень взаимонепонимания, а кое кто не потрудился понять, на что же он все таки отвечал.
Я уже прояснил, на что именно я отвечал. И там вариантов и нет особо.
НС>Возможно. Но это не может быть реализовано статически. На статику можно заменить реализацию визитора, но нельзя сделать статическим сам механизм диспетчеризации. Как нельзя сделать полностью статическими мультиметоды или PM по АлгТД.
Мммм... как нудно и как далеко от темы.
Что есть "статически" применительно к С++:
— инлайновость
— оптимизации на основе видимости конкретных типов и значений
— выкидывание лишнего кода на основе анализа.
Т.к. ты фактически воспринимаешь менее из 50% того, что я тебе пишу, поэтому рассмотрю подробный пример.
Берем некоего посетителя БЕЗ виртуальных методов...
Ну реально, абстракция посетителя на интерфейсах в условиях шаблонов С++ не нужна. Более того, в классической двойной диспетчеризации достаточно сделать абстрактным лишь один объект, а вторая часть диспетчеризации выполняется прямо в теле виртуального метода, вызывая нужную перегрузку первого участника мультиметода. Т.е. зачем в двойной диспетчеризации еще третий шаг этой диспетчеризации — непонятно.
Шаг второй, расмотрим, когда объект сам обходит свою структуру, т.е. вызывет visit() для объектов разных типов. Фишка в том, что эти объекты так же не объязаны быть из одного корня. Один корень в классическом ООП используется там для повторного использования кода, т.е. для реализация метода accept() лишь однажды в базе.
Но, однократную реализацию можно сделать и на шаблонах C++:
template<typename ConcreteVisitable>
class Visitable {
public:
template<typename Visitor>
void visit(Visitor * visitor) {
visitor->accept(static_cast<ConcreteVisitable*>(this));
}
};
class SomeElement1 : public Visitable<SomeElement1>
{
};
class SomeElement2 : public Visitable<SomeElement1>
{
};
template<typename Type1, typename Type2>
class BinaryElement {
Type1 elem1;
Type2 elem2;
public:
template<typename Visitor>
void visit(Visitor * visitor) {
elem1.visit(visitor);
elem2.visit(visitor);
}
}
...
BinaryElement<SomeElement1, SomeElement2> binElem;
ConcreteVisitor visitor;
binElem.visit(&visitor);
Фишка в том, что SomeElement1 и SomeElement2 не имеют общий корень. Вот такая особенность наследования от шаблонов. Они наследуют 2 разных типа: Visitable<SomeElement1> и Visitable<SomeElement2>.
Особенно всё прикольно выходит, когда приличную часть функциональности целевого accept тоже делают шаблонным. Для чего же здесь тогда двойной вызов? А читаем еще раз ПРОБЛЕМАТИКУ в описании паттерна. Т.е. когда нам потребуются реализации accept, не описываемые в общем виде на шаблонах, то мы сможем эту реализацию менять/добавлять, не трогая клиентские классы.
В примере был показан случай полностью статической диспетчеризации на шаблонах. В этом случае, когда компилятор видит все типы и может их вывести — происходит статический вызов прямо нужного метода, а учитывая инлайновость, и обычно легковесность операций... в общем, там затраты в сравнении с затратами в варианте на виртуальных ф-иях отличаются более чем на порядок в реальной жизни. Так же в реальной жизни это решение обычно комбинированное, например, если есть некая коллекция верхнего уровня, то её участники могут поддерживать некий общий интерфейс. Но после этой "точки входа" весь обход может идти уже статически. Что мы имеем — фактической использование одной и той же реализации для обоих случаев, полная идентичность дизайна, легкость в переходе на реализацию на виртуальных ф-иях или обратно в статику (базу поменяли и всех делов).
Т.е. тот факт, что зачастую всё проиходит в статике — это можно принять за внутреннее дело компилятора. Можно считать, что мы о ней не знаем, и честно пишем себе классического визитора. А так оно и есть, техника двойной диспетчеризации по-прежнему нужна (пусть даже она порой работает лишь на этапе компиляции), чтобы выйти на конкретный мультиметод, который опять же компилятор вправе "раскрутить" и сделать из него обычную ф-ию, если у него хватает информации.
И напоследок: насчет алгТД и паттерн-матчинга ты категорически не прав. Если оптимизирующий компилятор видит весь пусть возникновения значения, то вместо диспетчеризации в runtime он может сделать это же в compile-time. Фактически, это суперкомпиляция, которая стирает границы м/у runtime и compile-time. И опять же фактически, С++ стал суперкомпилятором с тех пор, как в него вошли inline функции и методы. И вот это всё "статикой" в С++ и называется, т.е. еще раз для закрепления: 1. возможность писать обобщенный код, который в ходе компилирования инстанциируется до конкретных типов, не требуя в 99% случаев применения техники абстрактных классов (в сравнении с Pascal/Java/C#/...), 2. суперкомпиляция, умеющая часть вычислений производить в compile-time, подменяя динамику на статику.
Здравствуйте, hattab, Вы писали:
H>Здравствуйте, dim-s, Вы писали:
d>> Ну на счет тормознутости генерируемого asm кода fpc я бы не сказал, максимум он отстает на 20%.
H>Я как то тестировал на своих задачах — ~30%. С вариантами вообще 40%. Можешь сам проверить: H>
H> v : Variant;
H> i : Integer;
H> v := 1;
H> for i := 1 to 100000000 do
H> v := v + v / v;
H>
H>Delphi 2010 — 9 сек. FPC 2.5.1 — 15 сек.
d>> Знаю что там тормознутый SetLength например, но можно же использовать функции для выделения памяти, что и сделано в реализации TList и т.п. Например TList в лазарусе быстрее чем в делфи
H>С чего бы TList'у в FPC быть быстрее дельфийского, когда они реализованы одинаково?
d>>, а юникод в Гуи был с самого начала, но там как-то так сделали, что нет проблем с ansistring и юникодным gui.
H>Ну в гуе у них Linux way Сделали UTF-8 в ансистроках.
d>> У меня были некоторые тесты, где fpc выигрывал у делфи в 4-5 раз, а было и наоборот.
H>Как говорится, тесты в студию! Самому интересно посмотреть.
Ты учти, в режиме отладки в среде lazarus код может замедлятся в 2-50 раз, я сам был в шоке, вот ты проверь скорость без среды, просто запусти ехе и проверь. У меня был прикол TFPList отец TList работал в 10 раз медленнее почему-то, после чего оказалось из-за отладки.
Здравствуйте, dim-s, Вы писали:
d> Ты учти, в режиме отладки в среде lazarus код может замедлятся в 2-50 раз, я сам был в шоке, вот ты проверь скорость без среды, просто запусти ехе и проверь. У меня был прикол TFPList отец TList работал в 10 раз медленнее почему-то, после чего оказалось из-за отладки.
Ну, что я маленький, время мерять из среды да еще и не на релиз настройках Все по честному для обоих проектов: Настройки компилятора — максимум оптимизации, отключение всех проверок, выкидывание дебаг-инфо. Включение режима High Performance (чтоб Cool'n'Quiet на результат не повлиял) и несколько запусков каждого теста (оба проекта консольные, замерялось только время цикла).
Здравствуйте, hattab, Вы писали:
H>Здравствуйте, dim-s, Вы писали:
d>> Ты учти, в режиме отладки в среде lazarus код может замедлятся в 2-50 раз, я сам был в шоке, вот ты проверь скорость без среды, просто запусти ехе и проверь. У меня был прикол TFPList отец TList работал в 10 раз медленнее почему-то, после чего оказалось из-за отладки.
H>Ну, что я маленький, время мерять из среды да еще и не на релиз настройках Все по честному для обоих проектов: Настройки компилятора — максимум оптимизации, отключение всех проверок, выкидывание дебаг-инфо. Включение режима High Performance (чтоб Cool'n'Quiet на результат не повлиял) и несколько запусков каждого теста (оба проекта консольные, замерялось только время цикла).
Оптимизация -Or включена? — Хранить некоторые переменные в регистрах.
К тому же я просто никогда не пользуюсь Variant'ом. Могу скинуть один класс, в котором делфи проигрывает в 4 раза, класс называется TStringArray, это почти TStringList, но там выделение памяти идет кусками, за счет чего добавление нового элемента в список становится намного быстрее.
Здравствуйте, dim-s, Вы писали:
d> Оптимизация -Or включена? — Хранить некоторые переменные в регистрах.
Включена.
d> К тому же я просто никогда не пользуюсь Variant'ом.
Зато он используется в db-access компонентах, да и вообще, варианты это частный случай. У меня и на чисто вычислительных алгоритмах FPC проседал
d> Могу скинуть один класс, в котором делфи проигрывает в 4 раза, класс называется TStringArray, это почти TStringList, но там выделение памяти идет кусками, за счет чего добавление нового элемента в список становится намного быстрее.
Т.е. код будучи скомпилирован в дельфях сольет в 4 раза скомпилированному в FPC? Давай код, будем посмотреть
Здравствуйте, Ночной Смотрящий, Вы писали:
I>>Вообще говоря визитор это не только когда диспетчеризация по типам с общим корнем.
НС>Вообще говоря только. По определению. НС>
НС>... the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves; instead, one creates a visitor class that implements all of the appropriate specializations of the virtual function. The visitor takes the instance reference as input, and implements the goal through double dispatch.
НС>Википедия
Мухлёшь. Определение шло выше, и оно практически идентично описанной проблематике из GOF:
In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure it operates on. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. It is one way to easily follow the open/closed principle.
А конкретно это предложение начиналось так: In essence, the visitor allows...
Самиздат, короче, очередного "толкователя Торы", нихрена не понявшего проблематику паттерна, а заметившего эффект, аналогичный переопределению виртуальных ф-ий для случая иерархии посещаемых. И ведь не сообразил, что если посещаемые не будут из одного корня, то описанный эффект всё-равно сохраняется.
Здравствуйте, hattab, Вы писали:
H>Здравствуйте, dim-s, Вы писали:
d>> Оптимизация -Or включена? — Хранить некоторые переменные в регистрах.
H>Включена.
d>> К тому же я просто никогда не пользуюсь Variant'ом.
H>Зато он используется в db-access компонентах, да и вообще, варианты это частный случай. У меня и на чисто вычислительных алгоритмах FPC проседал
d>> Могу скинуть один класс, в котором делфи проигрывает в 4 раза, класс называется TStringArray, это почти TStringList, но там выделение памяти идет кусками, за счет чего добавление нового элемента в список становится намного быстрее.
H>Т.е. код будучи скомпилирован в дельфях сольет в 4 раза скомпилированному в FPC? Давай код, будем посмотреть
Не знаю я писал компилятор байт-кода и виртуальную машину на делфи, там использовались массивы, выделение памяти, классы, объекты. FPC проигрывает иногда 10-20%, иногда не проигрывает.
Здравствуйте, dim-s, Вы писали:
d> H>Т.е. код будучи скомпилирован в дельфях сольет в 4 раза скомпилированному в FPC? Давай код, будем посмотреть
d> Не знаю я писал компилятор байт-кода и виртуальную машину на делфи, там использовались массивы, выделение памяти, классы, объекты. FPC проигрывает иногда 10-20%, иногда не проигрывает.
d> А вот класс можно посмотреть тут: http://code.google.com/p/orionphp/source/browse/trunk/libs/ori_FastArrays.pas
Uses
sysutils, ori_FastArrays;
Var
i : Integer;
sa : TStringArray;
begin
sa := TStringArray.Create;
WriteLn(DatetimeToStr(Now));
for i := 1 to 100000000 do
sa.Add('');
WriteLn(DatetimeToStr(Now));
end.
Delphi 2010 — 2 сек. FPC 2.5.1 — не дождался завершения, время пошло на минуты (явно у него чего-то с менеджером памяти).
Здравствуйте, hattab, Вы писали:
H>Здравствуйте, Феоктистов Александр, Вы писали:
ФА>> да fastmm не хватает в fpc...
H>Странно, почему не используют, open source же
Потому что его нереально сделать кроссплатформенным. Потеря скорости, все из-за кроссплатформенности и ваш тест неадекватный, более 10 млн строк fpc не в состоянии быстро выделить. Поэтому такие тормоза, не знаю, в моем проекте, когда все в комплексе разница не такая уж большая.
Здравствуйте, dim-s, Вы писали:
d> ФА>> да fastmm не хватает в fpc...
d> H>Странно, почему не используют, open source же
d> Потому что его нереально сделать кроссплатформенным. Потеря скорости, все из-за кроссплатформенности
Почему они не могут использовать FastMM, когда проект собирается для x86 (коли) Других то привязок, кроме ассемблера, там нет.
d> и ваш тест неадекватный, более 10 млн строк fpc не в состоянии быстро выделить. Поэтому такие тормоза, не знаю, в моем проекте, когда все в комплексе разница не такая уж большая.
Дело тут не в адекватности теста (а бенчи они никогда адекватными не бывают), а в том, что менеджер памяти FPC сливает со свистом на сценариях требующих частой аллокации и переаллокации (кстати, строки там выделять не требуется т.к. пустая строка это nil, и там по сути происходит хранение пустых указателей, с вызовом соответствующих функций выполняющих присваивание строк). И такие сценарии отнюдь не редкость. Хорошо. Заменим TStringArray на TPtrArray в этом тесте.
Uses
sysutils, ori_FastArrays;
Var
i : Integer;
sa : TPtrArray;
begin
sa := TPtrArray.Create;
WriteLn(DatetimeToStr(Now));
for i := 1 to 100000000 do
sa.Add(nil);
WriteLn(DatetimeToStr(Now));
Delphi 2010 — 1 сек. FPC 2.5.1 — я снова не дождался
Здравствуйте, gandjustas, Вы писали:
G>STL как раз упрощает C++: по-максимуму прячет указатели, реализацию строк и работу с динамической памятью. Это как раз те аспекты С++, которые делают его переусложненным.
Разве прячет динамическую память? Я бы так не сказал. Можно свои аллокаторы определять.
Итераторы вместо указателей тоже не совсем безопасно, можно легко аналогичные проблемы поиметь.
Имхо, основное удобство STL — разделение алгоритмов и контейнеров, предикаты, функциональные объекты.
Легкость описания сложных алгоритмов обработки данных в сочетании с широким полем деятельности для оптимизатора, после раскрытия шаблонов.
HA>Разве прячет динамическую память? Я бы так не сказал. Можно свои аллокаторы определять.
Прячет, аллокаторы определять по умолчанию не нужно.
И между просто объявлением std::vaector<..> и плясками с new/delete разница огромная, не говоря уже
о resize и push_back
HA>Итераторы вместо указателей тоже не совсем безопасно, можно легко аналогичные проблемы поиметь.
Это да, дань эффективности. Тут Степанов сделал ошибку, хотя если учесть когда это разрабатывалось то простительную.
Здравствуйте, Head Ache, Вы писали:
HA>Здравствуйте, gandjustas, Вы писали:
G>>STL как раз упрощает C++: по-максимуму прячет указатели, реализацию строк и работу с динамической памятью. Это как раз те аспекты С++, которые делают его переусложненным.
HA>Разве прячет динамическую память? Я бы так не сказал. Можно свои аллокаторы определять.
Тем не менее с использованием STL писать new, а тем более delete, приходится в разы меньше.
HA>Итераторы вместо указателей тоже не совсем безопасно, можно легко аналогичные проблемы поиметь.
Это если итератор по вектору, то да. А по другим контейнерами — нет.
HA>Имхо, основное удобство STL — разделение алгоритмов и контейнеров, предикаты, функциональные объекты. HA>Легкость описания сложных алгоритмов обработки данных в сочетании с широким полем деятельности для оптимизатора, после раскрытия шаблонов.
Не спорю. Я говорю не о сути, а о влиянии на язык\программы.
Здравствуйте, Ночной Смотрящий, Вы писали:
I>>Joshua Kerievsky
НС>Нет, ты определение давай. Или предлагаешь мне все сочинения этого автора перечитать?
У него есть книга, рефакторинг с использованием паттернов. Вот туда и смотри. Ссылок на эту книгу у меня нет.
Здравствуйте, vdimas, Вы писали:
I>>Т.е. это нечто, что выглядит как функция, но ею не является и по этой причине вводит в заблуждение + затрудняет понимание — это как раз про СТЛ и БУСТ.
V>Что значит "ею не является"? В STL и boost во всех местах, где можно подать как параметр обычную ф-ию, можно подать и функтор (функциональный объект в терминах С++).
Это и значит, что не является — два разных типа с разными возможностями. Реально даже три — указатели на методы та еще дрянь. В итоге надо постоянно приседать вокруг этого, особенно если пишешь какое то расширение.
V>И поясни, плиз, что именно вводит в заблуждение, и в чем состоит само заблуждение?
см выше
V>-------------------------- V>Я было хотел начать пояснять прямо тут, но гугл по фразе "функтор С++" вываливает более доходчивую инфу.
Что такое функтор я знал задолго до того, как ты на этом сайте зарегился.
Здравствуйте, gandjustas, Вы писали:
I>>В задаче нужно найти покрытие для которого функция минимальна I>>Очевидно — задача слишком сложная, что бы мерять её ради форумной баталии. Потому я предложил тебе упрощенный случай — только первую фазу, поиск всех маршрутов. G>Ну я даже не удивлен что ты снова поменял условия задачи.
Я ничего не менял
I>>Код я скипнул, потому что ты поторопился с решением. В этой функции нельзя заранее отсекать варианты Потому еще раз — лучше ограничиться только поиском всех маршрутов — первая фаза. G>Это как раз прекрасно делает ленивый вариант обхода.
Делает. И заметь — универсальность сама собой куда то пропала потому что возвращается IEnumerable<IEnumerable<T>>, а ленивость ни одного преимущества не дает. Ленивость нужна когда с большой вероятностью не нужен полный перебор. В задаче, которую я тебе показал, ленивые переборы себя _не_ _оправдали_.
G>Ты не привел ни одного обоснования своим словам, ни про размер кода, ни про быстродействие, ни про визиторы, постоянно пытаешься увильнуть.
С перформансом все достаточно просто — императивная версия оптимизирована под _массив_, по скорости она чуток уступает С++. Именно те рекурсивные, что я приводил, не тестировались, но Linq-оверхед будет медленеее чистой рекурсии это ты сам знаешь. Тест для JS V8 в принципе можно оформить, но на это пока нет времени, т.к. для теста надо поработать
Про визиторы уже вроде все сказано. Размер кода сам сравнить можешь. При одинаковом кол.ве строк твой код больше чем в двое шире из за дурацкого синтаксиса
function AllRoutes(root, createRoute){
var route = new List();
var routes = new List();
(function (v){
route.Push(v);
routes.Push(createRoute(route));
if(!route.Contains(v))
for(x in v.Connections)
arguments.callee(x);
route.Pop();
})(root);
return routes;
}
G>Кстати с чего все началось: для обхода графов вполне достаточно Linq и комбинаторов.
Linq можно использовать, только надо ли, если код превращается непойми во что да еще становится длиннее ажно вдвое ? И при этом ни универсальности ни быстродействия даже MemoizeAll не спасает
Здравствуйте, hattab, Вы писали:
H>Я как то тестировал на своих задачах — ~30%. С вариантами вообще 40%. Можешь сам проверить:
... H>Delphi 2010 — 9 сек. FPC 2.5.1 — 15 сек.
Вероятно, цифры ты взял с потолка, т.к. у тебя 66% а не 40
Здравствуйте, gandjustas, Вы писали:
HA>>Разве прячет динамическую память? Я бы так не сказал. Можно свои аллокаторы определять. G>Тем не менее с использованием STL писать new, а тем более delete, приходится в разы меньше.
Это как бы так, зато гораздо сложнее становится узнать, когда же надо писать new/delete и конструкторы всякие, а когда нет.
Здравствуйте, Ikemefula, Вы писали:
I> H>Я как то тестировал на своих задачах — ~30%. С вариантами вообще 40%. Можешь сам проверить:
I> ...
I> H>Delphi 2010 — 9 сек. FPC 2.5.1 — 15 сек.
I> Вероятно, цифры ты взял с потолка, т.к. у тебя 66% а не 40
Здравствуйте, Ikemefula, Вы писали:
G>>Тем не менее с использованием STL писать new, а тем более delete, приходится в разы меньше.
I>Это как бы так, зато гораздо сложнее становится узнать, когда же надо писать new/delete и конструкторы всякие, а когда нет.
Не становится, правило очень простое, new писать только в конструкторах умных указателей, delete в прикладном коде не использовать никогда.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
I>>>В задаче нужно найти покрытие для которого функция минимальна I>>>Очевидно — задача слишком сложная, что бы мерять её ради форумной баталии. Потому я предложил тебе упрощенный случай — только первую фазу, поиск всех маршрутов. G>>Ну я даже не удивлен что ты снова поменял условия задачи. I>Я ничего не менял
Ага, ты не сообщал все условия, это по сути то же самое.
I>>>Код я скипнул, потому что ты поторопился с решением. В этой функции нельзя заранее отсекать варианты Потому еще раз — лучше ограничиться только поиском всех маршрутов — первая фаза. G>>Это как раз прекрасно делает ленивый вариант обхода.
I>И заметь — универсальность сама собой куда то пропала потому что возвращается IEnumerable<IEnumerable<T>>, а ленивость ни одного преимущества не дает.
не понял фразы. Ты можешь придумать более универсальный интерфейс чтобы вернуть все маршруты на графе?
I>Ленивость нужна когда с большой вероятностью не нужен полный перебор. В задаче, которую я тебе показал, ленивые переборы себя _не_ _оправдали_.
Ты скрыл важные детали до того как я показал код. Теперь не строй из себя самого умного.
G>>Ты не привел ни одного обоснования своим словам, ни про размер кода, ни про быстродействие, ни про визиторы, постоянно пытаешься увильнуть. I>С перформансом все достаточно просто — императивная версия оптимизирована под _массив_, по скорости она чуток уступает С++. Именно те рекурсивные, что я приводил, не тестировались, но Linq-оверхед будет медленеее чистой рекурсии это ты сам знаешь. Тест для JS V8 в принципе можно оформить, но на это пока нет времени, т.к. для теста надо поработать
Ты как-то забыл что мой код с небольшими усилиями можно распараллелить. Каких усилий будет стоить сделать то же самое на C++ или на JS?
Вообще сейчас любой переборной алгоритм надо параллелить.
I>Про визиторы уже вроде все сказано. Размер кода сам сравнить можешь. При одинаковом кол.ве строк твой код больше чем в двое шире из за дурацкого синтаксиса I>
I>function AllRoutes(root, createRoute){
I> var route = new List();
I> var routes = new List();
I> (function (v){
I> route.Push(v);
I> routes.Push(createRoute(route));
I> if(!route.Contains(v))
I> for(x in v.Connections)
I> arguments.callee(x);
I> route.Pop();
I> })(root);
I> return routes;
I>}
I>
Ты как-то опять обошел вниманием что мой код:
1)Довольно легко распараллелить
2)Обобщенный
Добейся в коде выше тех же характеристик, тогда поговорим.
G>>Кстати с чего все началось: для обхода графов вполне достаточно Linq и комбинаторов. I>Linq можно использовать, только надо ли, если код превращается непойми во что да еще становится длиннее ажно вдвое ?
Неверно, ибо один и тот же код обхода можно использовать для любых графов.
I>И при этом ни универсальности ни быстродействия даже MemoizeAll не спасает
MemoizeAll не для быстродействия, а для однократного появления сайд-эффектов, а универсальности более чем достаточно.
Здравствуйте, FR, Вы писали:
I>>Это как бы так, зато гораздо сложнее становится узнать, когда же надо писать new/delete и конструкторы всякие, а когда нет.
FR>Не становится, правило очень простое, new писать только в конструкторах умных указателей, delete в прикладном коде не использовать никогда.
Шота я смотрю, это простое правило мало у кого получается применить
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
HA>>>Разве прячет динамическую память? Я бы так не сказал. Можно свои аллокаторы определять. G>>Тем не менее с использованием STL писать new, а тем более delete, приходится в разы меньше.
I>Это как бы так, зато гораздо сложнее становится узнать, когда же надо писать new/delete и конструкторы всякие, а когда нет.
Простые правила:
1)Если не писал new — не пиши delete
2)Если хочешь написать new, то не пиши delete, а используй один из классов умных указателей.
3)Никогда не возвращай обычный указатель из функции.
Только тогда C++ из сверх-супер-пупер-мега быстрого монстра превращается маленького пушистого котенка.
G>Ты как-то забыл что мой код с небольшими усилиями можно распараллелить. Каких усилий будет стоить сделать то же самое на C++ или на JS? G>Вообще сейчас любой переборной алгоритм надо параллелить.
Империя зла нас плюсистов не обделила на этот раз:
Здравствуйте, gandjustas, Вы писали:
G>>>Ну я даже не удивлен что ты снова поменял условия задачи. I>>Я ничего не менял G>Ага, ты не сообщал все условия, это по сути то же самое.
Я сразу сказал, что реальную задачу слишком сложно описать и решить
I>>И заметь — универсальность сама собой куда то пропала потому что возвращается IEnumerable<IEnumerable<T>>, а ленивость ни одного преимущества не дает. G>не понял фразы. Ты можешь придумать более универсальный интерфейс чтобы вернуть все маршруты на графе?
Ты всегда начинаешь со второстепенных требований ?
I>>Ленивость нужна когда с большой вероятностью не нужен полный перебор. В задаче, которую я тебе показал, ленивые переборы себя _не_ _оправдали_. G>Ты скрыл важные детали до того как я показал код. Теперь не строй из себя самого умного.
Я ничего не скрывал кроме самого решения Тебе нужно было не валять дурака а сразу написать AllRoutes и все дела.
G>Ты как-то забыл что мой код с небольшими усилиями можно распараллелить. Каких усилий будет стоить сделать то же самое на C++ или на JS? G>Вообще сейчас любой переборной алгоритм надо параллелить.
Распараллеливается на раз и еще легче чем тебе кажется
G>Ты как-то опять обошел вниманием что мой код: G>1)Довольно легко распараллелить
см выше
G>2)Обобщенный
и толку в этом никакого
G>Добейся в коде выше тех же характеристик, тогда поговорим.
Твой код обладает перформансом ниже плинтуса.
I>>Linq можно использовать, только надо ли, если код превращается непойми во что да еще становится длиннее ажно вдвое ? G>Неверно, ибо один и тот же код обхода можно использовать для любых графов.
1 Не для любых 2 с потерей перформанса
I>>И при этом ни универсальности ни быстродействия даже MemoizeAll не спасает G>MemoizeAll не для быстродействия, а для однократного появления сайд-эффектов, а универсальности более чем достаточно.
Универсальность без перформанса никому не нужна в таких задачах.
Здравствуйте, gandjustas, Вы писали:
G>Простые правила: G>1)Если не писал new — не пиши delete G>2)Если хочешь написать new, то не пиши delete, а используй один из классов умных указателей. G>3)Никогда не возвращай обычный указатель из функции.
G>Только тогда C++ из сверх-супер-пупер-мега быстрого монстра превращается маленького пушистого котенка.
Спасибо, К.О. За 5 лет до твоей регистрации на РСДН я писал примерно тож самое.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
G>>>>Ну я даже не удивлен что ты снова поменял условия задачи. I>>>Я ничего не менял G>>Ага, ты не сообщал все условия, это по сути то же самое. I>Я сразу сказал, что реальную задачу слишком сложно описать и решить
Тем не менее продолжал что-то доказывать, хотя фактически не привел оснований.
I>>>И заметь — универсальность сама собой куда то пропала потому что возвращается IEnumerable<IEnumerable<T>>, а ленивость ни одного преимущества не дает. G>>не понял фразы. Ты можешь придумать более универсальный интерфейс чтобы вернуть все маршруты на графе? I>Ты всегда начинаешь со второстепенных требований ?
Не меняй тему, ответь на вопрос.
I>>>Ленивость нужна когда с большой вероятностью не нужен полный перебор. В задаче, которую я тебе показал, ленивые переборы себя _не_ _оправдали_. G>>Ты скрыл важные детали до того как я показал код. Теперь не строй из себя самого умного. I>Я ничего не скрывал кроме самого решения
И задачи
I>Тебе нужно было не валять дурака а сразу написать AllRoutes и все дела.
Так ты не мог объяснить что есть route
G>>Ты как-то забыл что мой код с небольшими усилиями можно распараллелить. Каких усилий будет стоить сделать то же самое на C++ или на JS? G>>Вообще сейчас любой переборной алгоритм надо параллелить. I>Распараллеливается на раз и еще легче чем тебе кажется
Покажи код. Иначе не верю.
G>>Ты как-то опять обошел вниманием что мой код: G>>1)Довольно легко распараллелить I>см выше
G>>2)Обобщенный I>и толку в этом никакого
Ну да, кроме того что меньше кода писать — действительно никакого.
G>>Добейся в коде выше тех же характеристик, тогда поговорим. I>Твой код обладает перформансом ниже плинтуса.
Давай тестовые данные, проведем забеги.
I>>>Linq можно использовать, только надо ли, если код превращается непойми во что да еще становится длиннее ажно вдвое ? G>>Неверно, ибо один и тот же код обхода можно использовать для любых графов. I>1 Не для любых 2 с потерей перформанса
1 — докажи, 2 — докажи
I>>>И при этом ни универсальности ни быстродействия даже MemoizeAll не спасает G>>MemoizeAll не для быстродействия, а для однократного появления сайд-эффектов, а универсальности более чем достаточно. I>Универсальность без перформанса никому не нужна в таких задачах.
Короче ты снова приводишь какие-то высказывания и не обосновываешь их. А там где очевидно неправ пытаешься сменить тему разговора.
С тебя:
1)Распараллеленный вариант allroutes
2)Формальное доказательство что не для любых графов подходит мой код
Без этого можешь и не писать. Полезного и умного в твоих практически нет.
Здравствуйте, gandjustas, Вы писали:
G>>>Ага, ты не сообщал все условия, это по сути то же самое. I>>Я сразу сказал, что реальную задачу слишком сложно описать и решить G>Тем не менее продолжал что-то доказывать, хотя фактически не привел оснований.
Тебе спецификацию что ли показать ? Я не уверен что ты сможешь её прочесть, если ты даже не знаешь что такое маршрут.
G>>>не понял фразы. Ты можешь придумать более универсальный интерфейс чтобы вернуть все маршруты на графе? I>>Ты всегда начинаешь со второстепенных требований ? G>Не меняй тему, ответь на вопрос.
Что же касается универсальности, то объясни, куда она девается если надо вдруг искать циклы ? Внезапно оказалось что твой универсальный подход стал вдруг частным случаем
I>>Тебе нужно было не валять дурака а сразу написать AllRoutes и все дела. G>Так ты не мог объяснить что есть route
Кто ж виноват, что ты не в теме и даже можешь отрыть википедию да глянуть что такое маршрут в графе.
I>>Распараллеливается на раз и еще легче чем тебе кажется G>Покажи код. Иначе не верю.
Про паралельный dfs написано достаточно много работ. См стр 328
G>>>2)Обобщенный I>>и толку в этом никакого G>Ну да, кроме того что меньше кода писать — действительно никакого.
У тебя кода БОЛЬШЕ. К тому же код ТОРМОЗНОЙ А распараллелить просто так не получится,нужно знать фокус параллелизации этого dfs. Я этот фокус знаю, а ты ?
I>>Твой код обладает перформансом ниже плинтуса. G>Давай тестовые данные, проведем забеги.
Все что надо я тебе уже дал. Если хочешь, что бы я поработал над этим какое то время, предложи чтото что может меня заинтересовать.
I>>>>Linq можно использовать, только надо ли, если код превращается непойми во что да еще становится длиннее ажно вдвое ? G>>>Неверно, ибо один и тот же код обхода можно использовать для любых графов. I>>1 Не для любых 2 с потерей перформанса G>1 — докажи, 2 — докажи
1 графы задаются разными способами, ты этого не знал ? вычислительная сложность алгоритма зависит от этого способа.
2 linq это _вагон_ _кода_,а у меня только чистая рекурсия. доказательсво см. в рефлекторе
G>Короче ты снова приводишь какие-то высказывания и не обосновываешь их. А там где очевидно неправ пытаешься сменить тему разговора. G>С тебя: G>1)Распараллеленный вариант allroutes
см выше
G>2)Формальное доказательство что не для любых графов подходит мой код
Ты хорошо понимаешь, что вычислительная сложность задач на графах зависит от способа представления графа ?
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, gandjustas, Вы писали:
G>>>>Ага, ты не сообщал все условия, это по сути то же самое. I>>>Я сразу сказал, что реальную задачу слишком сложно описать и решить G>>Тем не менее продолжал что-то доказывать, хотя фактически не привел оснований.
I>Тебе спецификацию что ли показать ? Я не уверен что ты сможешь её прочесть, если ты даже не знаешь что такое маршрут.
Ты опять пытаешься спрятать знания за терминами. А ты по-русски писать умеешь?
G>>>>не понял фразы. Ты можешь придумать более универсальный интерфейс чтобы вернуть все маршруты на графе? I>>>Ты всегда начинаешь со второстепенных требований ? G>>Не меняй тему, ответь на вопрос.
I>Что же касается универсальности, то объясни, куда она девается если надо вдруг искать циклы ? Внезапно оказалось что твой универсальный подход стал вдруг частным случаем
Да ну? Ты не сможешь найти циклы c кодом, который перебирает все пути на графе?
I>>>Тебе нужно было не валять дурака а сразу написать AllRoutes и все дела. G>>Так ты не мог объяснить что есть route I>Кто ж виноват, что ты не в теме и даже можешь отрыть википедию да глянуть что такое маршрут в графе.
Ссылку дай.
I>>>Распараллеливается на раз и еще легче чем тебе кажется G>>Покажи код. Иначе не верю.
I>Про паралельный dfs написано достаточно много работ. См стр 328 I>
Покажи код.
G>>>>2)Обобщенный I>>>и толку в этом никакого G>>Ну да, кроме того что меньше кода писать — действительно никакого. I>У тебя кода БОЛЬШЕ. К тому же код ТОРМОЗНОЙ А распараллелить просто так не получится,нужно знать фокус параллелизации этого dfs. Я этот фокус знаю, а ты ?
Может и знаешь, только как всегда никому не скажешь и не сделаешь. Все, отдыхай, надоело мне с тобой общаться. Ты очень умный, только слова свои никак не обосновываешь.
Здравствуйте, gandjustas, Вы писали:
I>>Тебе спецификацию что ли показать ? Я не уверен что ты сможешь её прочесть, если ты даже не знаешь что такое маршрут. G>Ты опять пытаешься спрятать знания за терминами. А ты по-русски писать умеешь?
Не тупи, открой букварь и прочти — http://tinyurl.com/4tzxe8v
I>>Что же касается универсальности, то объясни, куда она девается если надо вдруг искать циклы ? Внезапно оказалось что твой универсальный подход стал вдруг частным случаем G>Да ну? Ты не сможешь найти циклы c кодом, который перебирает все пути на графе?
У тебя в алгоритме та же ошибка, что и раньше
Вот тесткейс:
1 2
1 x
2 x
Ну и умора, задвигаешь тут про Linq, параллельность, а сам обойти граф не можешь Ц
"p=> !HasCycle(p)).Where(HasCycle).Select(ExtractCycle" — вот это буллшит, сложность выполнения резко выросла на N и распараллеливание тебе не поможет, разве что N будет равняться числу процессоров
I>>Кто ж виноват, что ты не в теме и даже можешь отрыть википедию да глянуть что такое маршрут в графе. G>Ссылку дай.
см выше
I>>Про паралельный dfs написано достаточно много работ. См стр 328 I>>
Ты дурак ? Код по ссылке.
G>Может и знаешь, только как всегда никому не скажешь и не сделаешь. Все, отдыхай, надоело мне с тобой общаться. Ты очень умный, только слова свои никак не обосновываешь.