Re[22]: собеседования, Реверс списка
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 16.10.13 10:53
Оценка:
Здравствуйте, vdimas, Вы писали:

I>>Решение проблемы с фрагментацией не сводится к написанию аллокатора, это всего лишь необходимая часть.

V>В плюсах сводится, что оч удобно. Однократно написанный сверхдешевый в разработке и в рантайм аллокатор юзается в сотнях продуктов.

Нет, не сводится. Я выделил, читай внимательнее.

I>>Вопрос — какое условие будет необходимым и достаточным ?


V>Вопрос я уже задавал рядом — нахрена нужен линейный массив в памяти с сотнями миллионов элементов?


Во первых, элементов может быть и меньше миллиона что бы вывалился OOM
Во вторых, промежуточные вычисления никто не отменял
Re[10]: собеседования, Реверс списка
От: Pavel Dvorkin Россия  
Дата: 16.10.13 11:39
Оценка: +1
Здравствуйте, Abyx, Вы писали:

A>это будет нарушением DRY, такой код сложно поддерживать.

A>когда надо будет что-то поменять, придется править больше строчек

А что тут вообще потребуется менять ?
И кстати, тебе не кажется , что заботясь о последующих модификациях (которые то ли будут, то ли нет), ты пока что делаешь менее эффективное (например) решение для данного кода, который реально будет работать ? То есть он будет хуже, чем он мог бы быть, и будет в таком виде работать. Это реально. А вот придется ли его модифицировать — это еще большой вопрос. В плане реверса списка — я, признаться, не очень вижу, что тут придется модифицировать когда бы то ни было.

Ну и безотносительно к списку. А ты уверен, что DRY — это прямо-таки принцип, от которого никогда нельзя отступать ? Ни при каких условиях ?

У меня такое впечатление, что современное программирование сформулировало ряд принципов (DRY в т.ч.), которые вообще-то сами по себе вовсе не плохи, но после этого почему-то возвело их в абсолют, и чуть ли не анафеме готово подвергнуть отступление от них. А они всего лишь некие рекомендации, со своей ценой, которую иногда стоит платить, а иногда и вовсе нет, так как цена слишком дорогой оказывается.

Вот ответь на такой вопрос. В твоем коде есть лишнее действие, как отметили до меня. Предположим, выяснится по результатам профилировки, что оно отнимает существенное время, и это существенно для программы. (Разумееется, я не говорю о твоем занулении next, я вообще). И вот выясняется, что со всеми хорошими принципами вроде DRY, модульности, выделения сущностей ты переписать этот код без этого лишнего действия не можешь Вопрос же такой — останешься при принципах и проиграешь в производительности , или же махнешь рукой на принципы и напишешь без них ?



PD>>Ну и чем это лучше. Ладно, о том, что это может быть менее эффективно (если не заинлайнится) — промолчу. Но и просто по стилю — чем это лучше ? Чем это понятнее ? Мне надо отвлечься от чтения reverse, посмотреть код set_next, понять, что она делает, запомнить, что она делает (ее вызов может еще раз повториться, опять ее смотреть ?), потом вернуться к reverse и продолжить изучение. Хоть убей, не понимаю, чем это лучше простого присваивания полю.


A>в "p->next = cur;" используются четыре сущности — p, ->next, operator=, cur.

A>читается это как "в p, члену класса next, присвоить cur"

A>а в "set_next(p, cur);" используются три сущности — set_next, p, cur.

A>читается это примерно как "p set_next cur".
A>(c "p.set_next(cur)" было бы чуть проще, хотя использование явного или неявного this вобщем-то не важно)

Слушай, ты это серьезно ? Если впрямь серьезно, то у меня даже слов нет. Какая-то бессмысленная схоластика в совершенно примитивной ситуации.

A>смотреть реализацию set_next ни в коем случае не надо, она должна делать то что написано в ее названии — set next ListElement,


А отлаживать все же надо, и быть уверенным, что она делает именно то, что надо — все же придется.

A>преимущество в том, что вместо примитивных сущностей ->next и operator= мы используем более высокоуровневую операцию set_next (при этом мы не знаем ее реализацию).


Для меня — чистой воды схоластика.

A>и если постоянно использовать высокоуровневые операции, в т.ч. вместо "элемент newBegin присвоить NULL" — "новый список reversedList",

A>то код будет текстом описывающим операции над сущностями List и ListElement, а не мешаниной из присваиваний потрохов ListElement и каких-то переменных

Здесь мы не договоримся.

PD>>Да не надо тут долго смотреть. Берешь листочек, рисуешь список из трех элементов со стрелками, начинаешь выполнять на этом листочке, зачеркивая одни стрелки и рисуя другие. На втором элементе все будет ясно. Займет это минуту от силы.


A>я не хочу брать листочек и тратить минуту. я хочу разбираться с кодом с той скоростью с которой я его читаю


Что именно хочешь понять ? Что метод делает ? Для этого заголовка достаточно. Как работает ? Для этого придется в prepend и slice заглянуть — иначе откуда я могу быть уверен, что они именно то, что нужно делают ? По названию ? Тогда доверься Reverse по названию и не смотри его код. А иначе придется все же в них смотреть. И быстрее это не будет, в особенности с тем прототипом slice, о котором я писал. Там не одну минуту помедитируешь насчет того, всегда ли это верно работает. Да даже и без этого придется отвлечься от анализа Reverse, перейти к коду slice, потом вернуться... и хорошо если один раз.
With best regards
Pavel Dvorkin
Re[10]: собеседования, Реверс списка
От: Erop Россия  
Дата: 16.10.13 11:49
Оценка: +2
Здравствуйте, Abyx, Вы писали:

A>в "p->next = cur;" используются четыре сущности — p, ->next, operator=, cur.

A>читается это как "в p, члену класса next, присвоить cur"

A>а в "set_next(p, cur);" используются три сущности — set_next, p, cur.

A>читается это примерно как "p set_next cur".
A>(c "p.set_next(cur)" было бы чуть проще, хотя использование явного или неявного this вобщем-то не важно)


Знаешь, что? IMHO, если тебе доставляет сложности анализ и понимаени кода из этих семи присваиваний, то это, списки тебе лучше бы не разворачивать...

IMHO, это всё настолько просто и понятно, что пофигу. При этом ты напложил каких-то фантастических сущностей, про которые ещё не понятно что конкретно они делают и переусложнил всё раза в два, и втриаешь при этом про читабельность. А реально читабельные индентификаторы -- это есть хорошо. И кад в стиле "семь присваиваний" лучше бы ими снабдить, а пложение кучи функций с непонятными контрактами -- это плохо и переусложение...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: собеседования, Реверс списка
От: Erop Россия  
Дата: 16.10.13 11:54
Оценка:
Здравствуйте, Abyx, Вы писали:

A>я не хочу брать листочек и тратить минуту. я хочу разбираться с кодом с той скоростью с которой я его читаю


1) Тренеруйся
2) Код в защищаемом тоюой стиле лишь создаёт иллюзию понятности, то есть ты из него понимаешь, что хотел сказать автор, но то, что он действительно сказал наоборот тут сильнее спрятано...

Хинт: комментарии таки рулят
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: собеседования, Реверс списка
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 16.10.13 12:04
Оценка: +1 -2
Здравствуйте, Erop, Вы писали:

A>>я не хочу брать листочек и тратить минуту. я хочу разбираться с кодом с той скоростью с которой я его читаю


E>1) Тренеруйся


Тренироваться надо, но тем не менее код должен пониматься с той скоростью, с которой его читаешь. У Дворкина решение рабочее, но стиль написания примитивный, нужно вчитываться что бы понять.

У Abyx код предельно понятный сходу.

E>2) Код в защищаемом тоюой стиле лишь создаёт иллюзию понятности, то есть ты из него понимаешь, что хотел сказать автор, но то, что он действительно сказал наоборот тут сильнее спрятано...


Если код понятен с первого прочтения, то где эта самая иллюзия ?

E>Хинт: комментарии таки рулят


Комментарии это отстой. Комментарий всегда означает, что в коде существует проблема, но автору кода лень было решить её внятно и он накидал коментариев. Ну и коментарии нужно обновлять денно и нощно.
Re[11]: собеседования, Реверс списка
От: Abyx Россия  
Дата: 16.10.13 15:09
Оценка:
Здравствуйте, Erop, Вы писали:

E>Хинт: комментарии таки рулят


нет. комментарии врут.
In Zen We Trust
Re[11]: собеседования, Реверс списка
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 16.10.13 15:47
Оценка:
Здравствуйте, Erop, Вы писали:

E>Знаешь, что? IMHO, если тебе доставляет сложности анализ и понимаени кода из этих семи присваиваний, то это, списки тебе лучше бы не разворачивать...


Эта разница двух вариантов в присваиваниях на большом количестве кода будет только увеличиваться. Неважно, как хорошо ты умеешь читать код, на больших проектах низкоуровневый код ты прочитаешь и поймешь затратив на порядок больше времени.

E>IMHO, это всё настолько просто и понятно, что пофигу. При этом ты напложил каких-то фантастических сущностей, про которые ещё не понятно что конкретно они делают и переусложнил всё раза в два, и втриаешь при этом про читабельность. А реально читабельные индентификаторы -- это есть хорошо. И кад в стиле "семь присваиваний" лучше бы ими снабдить, а пложение кучи функций с непонятными контрактами -- это плохо и переусложение...


Если код такой простой то зачем тебе каменты ?
Re[18]: собеседования, Реверс списка
От: Ночной Смотрящий Россия  
Дата: 16.10.13 16:54
Оценка:
Здравствуйте, vdimas, Вы писали:

НС>>Это только если такая работа — единственная активность в процессе.

V>Коль речь о больших объемах памяти, то в любом случае это так

Практически всегда это не так.
Re[13]: собеседования, Реверс списка
От: Ночной Смотрящий Россия  
Дата: 16.10.13 16:54
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Возможно... Но мне даже трудно представить задачу, когда нам нужно десятки/сотни миллионов элементов в линейном массиве.


Сочувствую, чо.
Re[12]: собеседования, Реверс списка
От: Erop Россия  
Дата: 16.10.13 18:15
Оценка:
Здравствуйте, Abyx, Вы писали:

A>нет. комментарии врут.

Комментарии надо уметь читать...
Комментарии -- это лог намерений разработчика, а код -- то, что получилось из этих намерений.

А у тебя имена функций вместо комментариев используются, с той же степенью обязательности отсутствия вранья
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[18]: собеседования, Реверс списка
От: Evgeny.Panasyuk Россия  
Дата: 16.10.13 23:09
Оценка: 4 (2) :))
Здравствуйте, Erop, Вы писали:

E>Про С++ я рассказывал не потому, что там лучше или хуже, а потому, что про то, как в С++ я знаю. Я не думаю, что в С# как-то катастрофически хуже с этим делом и листом пользоваться нельзя-нельзя. Собственно я подставил под сомнение алармистское сообщение I. именно в том смысле, то не верю, что всё настолько плохо и поинтересовался у экспертов в дотнете как оно есть на самом деле, а не в фантазиях нашего напуганного фрагментацией АП коллеги


Наткнулся на статью с примером.
Вкратце:
есть byte[] bigBlock; и есть List<byte[]> smallBlocks;
На каждой итерации вечного цикла bigBlock пересоздается с размером большим на единицу, начиная с 16 MiB,
а в smallBlocks добавляется new byte[90000].
После приёма OOM выводится количество занимаемых мебибайт блоками в smallBlocks.
Вроде бы не слишком сложная задача для нормального аллокатора, но у автора получилось всего-навсего 20MiB.

Проводим независимый тест:
VS2005: 21MiB
VS2008: 21MiB
VS2010: 622MiB
VS2012: 1738MiB
Делаем аналогичный тест на C++ VS2005: 1915MiB

Как видно секретные технологии аллокации медленным темпом утекают в .NET
Вот что говорит автор статьи:

[...] This might not seem so bad: surely the smaller blocks can be put in the large gaps that are left behind?
Well, they can, but there’s a catch. As mentioned previously, .NET prefers to put new memory blocks at the end of the heap, as it has to do less work to find a space where a block will fit: This means that when there’s a new large block on the heap, the next smaller block will be allocated immediately after it, with the consequence that it will have to further extend the heap if the program ever wants to allocate a larger block.

Что очень похоже на правду в случае VS2005 и VS2008.

Спекуляция на тему как всё это развивалось:
В .NET есть два типа кучи — для маленьких(Small Object Heap) и больших объектов(Large Object Heap).
Во время сборки мусора SOH компактифицируется, поэтому политика аллокации может быть простейшей, например просто добавление в конец, пока не упрёмся, а потом вызываем GC.
Большие объекты, передвигать накладно, поэтому эти ребята решили добавить LOH, в которой нет компактификации. Но, политику аллокации координатно не пересмотрели. Пользователи конечно же сказали им большое спасибо :

It really takes a large amount of chutzpah to release a product with such a major flaw. It basically makes it almost impossible to write long-running server processes in .NET. This issue almost cost my company a contract since we were experiencing inexplicable OutOfmemoryExceptions in a very important product.

The problem can be solved by
a) treating large objects like normal objects and compacting the LOH during a generation 2 collection or
b) using a classic heap management algorithm like the one from Donald Knuth to ensure that the total size of the heap never exceeds two times the total number of allocated bytes.

I don't expect microsoft to do anything about this issue. After all, they are busy adding new language features like dynamic to C# in order to make it more buzzword compliant. And they did not do anything about any of the other highly rated feedback items I have submitted. But I think everybody should know about this issue so that they can avoid the .NET platform for important applications.

Теперь же пытаются думать задним числом, постепенно улучшая аллокатор, и добавляя костыли типа ручного вызова компактификации.
Но у C#-истов осадочек-то остался, и боятся они теперь больших объектов как огня

Кстати, по поводу боязни растущих векторов — если заменить List<byte[]>, на List<byte>, и соответственно добавлять в него всё что раньше было в блоках — байт за байтом — то даже на VS2005 получается достичь "фантастических" 511MiB, потому что будут не тысячи LO, а всего два
Re[11]: собеседования, Реверс списка
От: Abyx Россия  
Дата: 17.10.13 00:02
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

A>>это будет нарушением DRY, такой код сложно поддерживать.

A>>когда надо будет что-то поменять, придется править больше строчек
PD>А что тут вообще потребуется менять ?

переименовать next в m_next например.

PD>И кстати, тебе не кажется , что заботясь о последующих модификациях (которые то ли будут, то ли нет), ты пока что делаешь менее эффективное (например) решение для данного кода, который реально будет работать ?

да, такая опасность есть. однако "эффективность кода" тоже нужна не всегда.

PD>Вот ответь на такой вопрос. В твоем коде есть лишнее действие, как отметили до меня. Предположим, выяснится по результатам профилировки, что оно отнимает существенное время, и это существенно для программы. (Разумееется, я не говорю о твоем занулении next, я вообще). И вот выясняется, что со всеми хорошими принципами вроде DRY, модульности, выделения сущностей ты переписать этот код без этого лишнего действия не можешь Вопрос же такой — останешься при принципах и проиграешь в производительности , или же махнешь рукой на принципы и напишешь без них ?


если нужна производительность, я напишу тот код, у которого будет большая производительность.

PD>Слушай, ты это серьезно ? Если впрямь серьезно, то у меня даже слов нет. Какая-то бессмысленная схоластика в совершенно примитивной ситуации.

серьезно.
это мелочь, но какая же важная мелочь, как например однообразное форматирование кода.

A>>я не хочу брать листочек и тратить минуту. я хочу разбираться с кодом с той скоростью с которой я его читаю

PD>Что именно хочешь понять ? Что метод делает ? Для этого заголовка достаточно. Как работает ? Для этого придется в prepend и slice заглянуть — иначе откуда я могу быть уверен, что они именно то, что нужно делают ? По названию ?
понять *как* работает метод, на уровне операций над списком.
для этого внутрь prepend и slice смотреть не надо.

вообще я согласен, из сигнатуры "Item* slice(Item*& head)" сложно понять что она делает. я впихнул в эту slice слишком много ответственностей, и она получилась непонятной.

насчет необходимости смотреть реализацию всех функций, тут есть один важный момент.
если работать с кодом использующим полиморфизм, то реализации посмотреть просто невозможно,
будь это статический полиморфизм template<class List> void reverse(List& lst) { ... prepend(elem, lst) ...
или динамический полиморфизм с IList.
In Zen We Trust
Re[12]: собеседования, Реверс списка
От: Erop Россия  
Дата: 17.10.13 04:37
Оценка: +1
Здравствуйте, Abyx, Вы писали:

A>переименовать next в m_next например.

А потом list в one_way_linked_nodes, скажем...
Бюджет-то на разработку резиновый, а решарпером ты из принципа не пользуешься, да?

A>да, такая опасность есть. однако "эффективность кода" тоже нужна не всегда.

Ну да, память и проц тоже резиновые, ага-ага...

A>это мелочь, но какая же важная мелочь, как например однообразное форматирование кода.


Суть проста. "правильное" форматирование кода нужно тока придуркам. Переведу на русский, если команда не может работать вместе из-за разногласий по форматированию, то её члены -- придурки.

При этом я не отрицаю, что когда однообразное форматирование есть, то это приятнее, но считать это "важным"?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: собеседования, Реверс списка
От: cosimo http://sapozhnikov.pro
Дата: 17.10.13 05:13
Оценка:
Здравствуйте, Erop, Вы писали:

E>Суть проста. "правильное" форматирование кода нужно тока придуркам.


Хм-хм. У меня был коллега, который писал C++ код без отступов, совсем, в столбик. После мержа приходилось прогонять исходник через code beautifier. И многие из вас не дрогнув ни единым мускулом на лице смогут работать с таким?
Re[19]: собеседования, Реверс списка
От: Sinix  
Дата: 17.10.13 05:35
Оценка: +3 -1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Теперь же пытаются думать задним числом, постепенно улучшая аллокатор, и добавляя костыли типа ручного вызова компактификации.

EP>Но у C#-истов осадочек-то остался, и боятся они теперь больших объектов как огня


Вы хоть чуть-чуть разберитесь, перед тем как писать. А то я вам тоже докажу, что c++ как огня боится перекрёстных ссылок, а haskell — мутабельных переменных
Re[12]: собеседования, Реверс списка
От: Pavel Dvorkin Россия  
Дата: 17.10.13 07:11
Оценка:
Здравствуйте, Abyx, Вы писали:

PD>>А что тут вообще потребуется менять ?


A>переименовать next в m_next например.


А как насчет переименования set_next в fill_next ?

PD>>И кстати, тебе не кажется , что заботясь о последующих модификациях (которые то ли будут, то ли нет), ты пока что делаешь менее эффективное (например) решение для данного кода, который реально будет работать ?

A>да, такая опасность есть. однако "эффективность кода" тоже нужна не всегда.

PD>>Вот ответь на такой вопрос. В твоем коде есть лишнее действие, как отметили до меня. Предположим, выяснится по результатам профилировки, что оно отнимает существенное время, и это существенно для программы. (Разумееется, я не говорю о твоем занулении next, я вообще). И вот выясняется, что со всеми хорошими принципами вроде DRY, модульности, выделения сущностей ты переписать этот код без этого лишнего действия не можешь Вопрос же такой — останешься при принципах и проиграешь в производительности , или же махнешь рукой на принципы и напишешь без них ?


A>если нужна производительность, я напишу тот код, у которого будет большая производительность.


Почему же ты тогда отстаиваешь свое решение с лишним действием ? Да, для списка — мелочь, но вопрос же в принципе. И речь идет ведь о коде неопределенного назначения, это тебе на обработка нажатия кнопки мыши , за которой следует чтение 10Мб файла, а поэтому можно сказать, что плевать мне на эффективность самого обработчика WM_LBUTTONDOWN. А вдруг где-то именно это лишнее присваивание вызовет потерю производительности ? И что тогда ? Копаться в этом slice, понять, что там лишнее действие, переделать все (его же просто так не уберешь там) ? Сколько времени уйдет на то, чтобы это место обнаружить ? Сколько времени уйдет, чтобы это исправить (то есть переписать в том виде, который я сделал) ? За это время я тебе все next в m_next в этом классе вручную переименую

PD>>Слушай, ты это серьезно ? Если впрямь серьезно, то у меня даже слов нет. Какая-то бессмысленная схоластика в совершенно примитивной ситуации.

A>серьезно.
A>это мелочь, но какая же важная мелочь, как например однообразное форматирование кода.

У меня такое впечатление складывается, что этот внешний антураж для тебя заслоняет то, ради чего код пишется. Форматирование можно потом каким-то форматтером сделать, и будет это третьестепенным действием. А вот некачественный код никаким форматированием не поправишь.
Для меня все же конфетка важнее фантика. Фантик можно потом и переделать/заменить, а вот если в конфету горчицу положили, то никакие фантики не помогут.

Кстати, с твоим примером насчет числа сущностей в p->next = cur (4) и set_next(p.cur) (3). А не готов ли ты в таком случае возразить против такого оператора

b = -b;

Тут ведь тоже 3 сущности (b, =, -), а можно бы обойтись двумя

neg(b);

И что, будем так и писать ?

A>вообще я согласен, из сигнатуры "Item* slice(Item*& head)" сложно понять что она делает. я впихнул в эту slice слишком много ответственностей, и она получилась непонятной.


A>насчет необходимости смотреть реализацию всех функций, тут есть один важный момент.

A>если работать с кодом использующим полиморфизм, то реализации посмотреть просто невозможно,
A>будь это статический полиморфизм template<class List> void reverse(List& lst) { ... prepend(elem, lst) ...
A>или динамический полиморфизм с IList.

Давай все же определись, о чем идет речь

1. Ты изучаешь класс, коду которого доверяешь. В этом случае тебе вообще незачем смотреть на реализацию. Сигнатуры Reverse достаточно (плюс док, если надо)
2. Ты изучаешь класс, код которого хочешь понять (неважно для чего). В этом случае тебе придется смотреть весь код.
Если встретится полиморфизм, то будет гибрид. Придется в отношении полиморфных функций использовать (1), поскольку и впрямь исследовать нельзя. Так сказать, констатируем факт — здесь у нас неизвестно что, но с указанной сигнатурой и описанием действий, остается надеяться, что оно работает правильно. Принудительно заставляем доверять, так сказать. В отношении остального — либо (1) либо (2) в зависимости от того, что имеет место.
With best regards
Pavel Dvorkin
Re[14]: собеседования, Реверс списка
От: Erop Россия  
Дата: 17.10.13 07:39
Оценка:
Здравствуйте, cosimo, Вы писали:

C>Хм-хм. У меня был коллега, который писал C++ код без отступов, совсем, в столбик. После мержа приходилось прогонять исходник через code beautifier. И многие из вас не дрогнув ни единым мускулом на лице смогут работать с таким?


Ну я бы просто кнопочку в IDE бы нажал, да и всё...
Тут есть такая проблема, что если форматирование какого-то исходника всё время меняется, это плохо сказывается на истории правок.
НО если вё сводится к расстановке пробелов/табов, то вообще всё пофиг же?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: собеседования, Реверс списка
От: Abyx Россия  
Дата: 17.10.13 08:41
Оценка: :)
Здравствуйте, Erop, Вы писали:

A>>это мелочь, но какая же важная мелочь, как например однообразное форматирование кода.


E>Суть проста. "правильное" форматирование кода нужно тока придуркам.

я сказал "однообразное", а не "правильное".
In Zen We Trust
Re[14]: собеседования, Реверс списка
От: Erop Россия  
Дата: 17.10.13 08:43
Оценка:
Здравствуйте, Abyx, Вы писали:

E>>Суть проста. "правильное" форматирование кода нужно тока придуркам.

A>я сказал "однообразное", а не "правильное".


А на воре-то и шапочка того-с...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[13]: собеседования, Реверс списка
От: Abyx Россия  
Дата: 17.10.13 09:20
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

A>>переименовать next в m_next например.

PD>А как насчет переименования set_next в fill_next ?

нет, переименование API происходит гораздо реже чем переименование реализации.

PD>>>И кстати, тебе не кажется , что заботясь о последующих модификациях (которые то ли будут, то ли нет), ты пока что делаешь менее эффективное (например) решение для данного кода, который реально будет работать ?

A>>да, такая опасность есть. однако "эффективность кода" тоже нужна не всегда.

PD>>>Вот ответь на такой вопрос. В твоем коде есть лишнее действие, как отметили до меня. Предположим, выяснится по результатам профилировки, что оно отнимает существенное время, и это существенно для программы. (Разумееется, я не говорю о твоем занулении next, я вообще). И вот выясняется, что со всеми хорошими принципами вроде DRY, модульности, выделения сущностей ты переписать этот код без этого лишнего действия не можешь Вопрос же такой — останешься при принципах и проиграешь в производительности , или же махнешь рукой на принципы и напишешь без них ?


A>>если нужна производительность, я напишу тот код, у которого будет большая производительность.


PD>Почему же ты тогда отстаиваешь свое решение с лишним действием ? Да, для списка — мелочь, но вопрос же в принципе. И речь идет ведь о коде неопределенного назначения, это тебе на обработка нажатия кнопки мыши , за которой следует чтение 10Мб файла, а поэтому можно сказать, что плевать мне на эффективность самого обработчика WM_LBUTTONDOWN. А вдруг где-то именно это лишнее присваивание вызовет потерю производительности ? И что тогда ? Копаться в этом slice, понять, что там лишнее действие, переделать все (его же просто так не уберешь там) ? Сколько времени уйдет на то, чтобы это место обнаружить ? Сколько времени уйдет, чтобы это исправить (то есть переписать в том виде, который я сделал) ? За это время я тебе все next в m_next в этом классе вручную переименую


компилятор уберет это лишнее присваивание.

PD>Кстати, с твоим примером насчет числа сущностей в p->next = cur (4) и set_next(p.cur) (3). А не готов ли ты в таком случае возразить против такого оператора

PD>b = -b;
PD>Тут ведь тоже 3 сущности (b, =, -), а можно бы обойтись двумя
PD>neg(b);
PD>И что, будем так и писать ?

да, я бы написал
struct Foo {
    void bar() { m_b = -m_b; }
private:
    int m_b;
};

если у Foo есть такая операция bar.

A>>вообще я согласен, из сигнатуры "Item* slice(Item*& head)" сложно понять что она делает. я впихнул в эту slice слишком много ответственностей, и она получилась непонятной.


A>>насчет необходимости смотреть реализацию всех функций, тут есть один важный момент.

A>>если работать с кодом использующим полиморфизм, то реализации посмотреть просто невозможно,
A>>будь это статический полиморфизм template<class List> void reverse(List& lst) { ... prepend(elem, lst) ...
A>>или динамический полиморфизм с IList.

PD>Давай все же определись, о чем идет речь


PD>1. Ты изучаешь класс, коду которого доверяешь. В этом случае тебе вообще незачем смотреть на реализацию. Сигнатуры Reverse достаточно (плюс док, если надо)

PD>2. Ты изучаешь класс, код которого хочешь понять (неважно для чего). В этом случае тебе придется смотреть весь код.
PD>Если встретится полиморфизм, то будет гибрид. Придется в отношении полиморфных функций использовать (1), поскольку и впрямь исследовать нельзя. Так сказать, констатируем факт — здесь у нас неизвестно что, но с указанной сигнатурой и описанием действий, остается надеяться, что оно работает правильно. Принудительно заставляем доверять, так сказать. В отношении остального — либо (1) либо (2) в зависимости от того, что имеет место.
третье. я доверяю коду класса, и я хочу понять как работает код некоторого метода.
например есть std::forward_list. я ему доверяю, он работает. но мне интересно как у него сделана reverse(), и я заглядываю внутрь ее реализации в VC++
и вижу что там используются empty, begin, before_begin, _Before_end — что они делают понятно из названия, реализацию смотреть не надо
еще там есть _Splice_same_after, смотрим ее сигнатуру — void _Splice_same_after(const_iterator _Where, _Myt& _Right, const_iterator _First, const_iterator _Last)
ок, значит она вставляет [first, last) после where, реализацию смотреть не надо
с этим знанием возвращаемся к reverse() и теперь понятно как она работает — берет элементы из начала списка и перемещает в конец.

...но тут возникает вопрос, а откуда _Before_end берет конец? смотрим ее реализацию, а там цикл. ...!@№? получается в VC++ reverse сделана со сложностью O(2N)
In Zen We Trust
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.