Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.137.218.230] |
|
Сообщ.
#1
,
|
|
|
Много статей развелось про чистоту кода (на основе книги Р.Мартина и не только). В целом концепция, конечно, хорошая.
Но бывают какие-то прямо абсурдные, ИМХО, рекомендации. Вот к примеру тут: // ???? const fetchData = (id) => { if (id) { fetch('/data/' + id) } } // ???? const fetchData = (id) => { if (!id) { return } fetch('/data/' + id) } И вот такие слова в конце статьи: Цитата «Погодите! А как насчет изменения производительности?». Мне это безразлично. Правда. Разве что есть реальная проблема, когда приложение становится медленнее, чем ожидалось. С таким мышлением закон Вирта совершенно не кажется "шуткой": Цитата Программы становятся медленнее куда шустрее, чем компьютеры становятся быстрее Далее, второй момент. Более "тонкий", скажем так. Example1 (кусочек кода): . . . while i*i <= n: k = 1 while n % i == 0: k += 2 n //= i result /= k i += 1 . . . Example2 (кусочек кода): . . . while i*i <= n: if n % i == 0: k = 3 while 1: n //= i if n % i: break k += 2 result /= k i += 1 . . . Второй вариант чуть более сложный для понимания (спасибо разработчикам Python'а за отсутствие do-while/repeat-until), но и чуть более оптимальный по скорости, ибо тут нет лишнего деления (ну и кое-чего ещё по мелочи). Согласен, не самый показательный пример (особенно учитывая, что это скриптовый язык, но давайте не будем обращать на это внимания, вникните в суть темы... представьте, что это C++ ). Собственно, можно особо не заморачиваться и использовать первый вариант. Но представим, что мы пишем библиотеку и не знаем как она будет использоваться. Насколько критична будет скорость в финальном коде? Ваши мысли обо всём этом безобразии... |
Сообщ.
#2
,
|
|
|
Не читай плохих статей! Создавать Elephantware имеет смысл только тогда, когда ты в пожизненной разработке проекта, и тебе оплачивают не качество, а количество доработок.
|
Сообщ.
#3
,
|
|
|
Цитата Jin X @ Не углубляйтесь в суть алгоритма, это неважно. как это не углубляйтесь? возможно там вообще деление не нужно |
Сообщ.
#4
,
|
|
|
Цитата villain @ Суть вообще не в этом. Будем считать, что алгоритм достаточно оптимален (это часть кода разложения на простые множители и манипуляции с ними), но есть 2 вот таких варианта реализации как это не углубляйтесь? возможно там вообще деление не нужно Там вообще умножение должно быть, я заменил его на деление для пущего эффекта |
Сообщ.
#5
,
|
|
|
Цитата JoeUser @ Не, ну понятно, что создавать класс в 3 поколения с 10 методами в каждом там, когда нужно сделать просто min(x,y) - это бред. Речь идёт именно о чистоте кода, а не о заделе на будущее. Т.е. о понятности кода тебе и людям с возможностью лёгкой модификации.Создавать Elephantware имеет смысл только тогда, когда ты в пожизненной разработке проекта, и тебе оплачивают не качество, а количество доработок. Реально ли (почти) всегда нужно писать одно действие-одна функция и выстраивать 5-этажные вызовы там, где можно было бы обойтись одной функцией? Реально ли (почти) всегда стоит заменять: // ???? people .filter(person => person.age > 10 && person.firstName.length > 2 && person.lastName.length > 4) // ???? people .filter(person => person.age > 10) .filter(person => person.firstName.length > 2) .filter(person => person.lastName.length > 4) |
Сообщ.
#6
,
|
|
|
Цитата Jin X @ Реально ли (почти) всегда стоит заменять: // ???? people .filter(person => person.age > 10 && person.firstName.length > 2 && person.lastName.length > 4) // ???? people .filter(person => person.age > 10) .filter(person => person.firstName.length > 2) .filter(person => person.lastName.length > 4) Можно еще вот так // ???? people.filter( person => person.age > 10 && person.firstName.length > 2 && person.lastName.length > 4 ) |
Сообщ.
#7
,
|
|
|
Цитата Jin X @ Ну что это за "красота" такая? Думаю, что тут имелся в виду принцип о размещении реакции на нарушения предусловий и обработки "внешних" ошибок в начале функций/методов. Как правило это действительно улучшает читаемость, поскольку дальнейшеая логика становится более простой. Добавлено Цитата Jin X @ И вот такие слова в конце статьи: Цитата «Погодите! А как насчет изменения производительности?». Мне это безразлично. Правда. Разве что есть реальная проблема, когда приложение становится медленнее, чем ожидалось. С таким мышлением закон Вирта совершенно не кажется "шуткой": Цитата Программы становятся медленнее куда шустрее, чем компьютеры становятся быстрее Ну портить код без оснований для улучшения производительности действительно не стоит. И вполне допустимо улучшить его там, где скорость не критична. Добавлено Цитата Jin X @ Но представим, что мы пишем библиотеку и не знаем как она будет использоваться. Совсем не знаем? Тогда зачем пишем? Добавлено Цитата Jin X @ Реально ли (почти) всегда стоит заменять: // ???? people .filter(person => person.age > 10 && person.firstName.length > 2 && person.lastName.length > 4) // ???? people .filter(person => person.age > 10) .filter(person => person.firstName.length > 2) .filter(person => person.lastName.length > 4) А здесь лучше читабельность? |
Сообщ.
#8
,
|
|
|
Цитата Jin X @ Какой же он оптимальный? Тут в каждом цикле два деления, когда можно обойтись одним. Второй вариант чуть более сложный для понимания (спасибо разработчикам Python'а за отсутствие do-while/repeat-until), но и чуть более оптимальный по скорости |
Сообщ.
#9
,
|
|
|
Цитата amk @ 2 деления во внешне цикле, 2 во внутреннем. Во втором примере при невыполнении условия внешнего цикла деление одно (в самом этом условии).Тут в каждом цикле два деления Цитата amk @ Мне вот даже интересно, как тут можно обойтись одним делением? когда можно обойтись одним. Добавлено А, ну вот вижу вроде в питоне есть функция divmod, но это для внешнего цикла только... а дальше? Добавлено Хотя нифига, divmod, как оказалось, работает медленнее (даже медленнее 2 вызовов: % и //) Добавлено Причём, я сейчас замерил скорость Example1 и Example2 (причём, с умножением, а не с делением result'а). Разница более 30%, о как! |
Сообщ.
#10
,
|
|
|
Цитата Jin X @ Т ак ты же вроде просил не обращать внимания на язык. В Си оптимизатор заменяет пару % / на одно деление. Вынесение одной из этих двух операций может сломать оптимизацию.Хотя нифига, divmod, как оказалось, работает медленнее (даже медленнее 2 вызовов: % и //) В любом случае нет смысла огород городить из-за всего одного сэкономленного деления. Судя по всему, это деление мало на что влияет. |
Сообщ.
#11
,
|
|
|
Цитата D_KEY @ Вот написал кто-то функцию power. Сразу понятно, где она может использоваться? Совсем не знаем? Тогда зачем пишем? Добавлено Цитата amk @ Т ак ты же вроде просил не обращать внимания на язык. Ну код же не на Си Но в любом случае % во внутреннем цикле и result /= k ты одним делением не сделаешь. Добавлено Но мы от сути вопроса отошли... |
Сообщ.
#12
,
|
|
|
Цитата Jin X @ Цитата D_KEY @ Вот написал кто-то функцию power. Сразу понятно, где она может использоваться? Совсем не знаем? Тогда зачем пишем? Да, практически везде, где будет применим сам язык. Значит это будет где-то в стандартной библиотеке и должно работать приемлемо во всех нишах, на которые рассчитан язык |
Сообщ.
#13
,
|
|
|
Цитата Jin X @ parseOne('code_1','js',false)preloadCodeButtons('1');Ну что это за "красота" такая? Тут видимо конфликт рекомендаций. Должно быть const fetchData = (id) => { if (!id) return; fetch('/data/' + id) } Но это противоречит безопасности if без else. Да и return по серёдке кода. . . . while i*i <= n: if n % i == 0: k = 3 while 1: n //= i if n % i: break k += 2 result /= k i += 1 . . . Цитата Jin X @ Второй вариант чуть более сложный для понимания (спасибо разработчикам Python'а за отсутствие do-while/repeat-until), Так там другой подход через множества. Данный код лишён контекста(окружения) поэтому сказать как его от рефакторить трудно. Но как минимум он напрашивается на разбиение на 2 функции. Скорее всего эти 2 функции можно нормально поименовать, внутрь вставить ваши оптимизации. А для того что-бы вызов функций не тормозил сделать их через шаблоны. Цитата Jin X @ Собственно, можно особо не заморачиваться и использовать первый вариант. Но представим, что мы пишем библиотеку и не знаем как она будет использоваться. Насколько критична будет скорость в финальном коде? Это смотря как писать. Вот к примеру есть математическая библиотека eigen легко читаемая оптимизированная и не уступает по скорости конкурентам. Или взять agg тоже качественный код. На самом деле я у себя сформировал комплект исходных кодов, которые счёл наиболее качественными. Цитата Jin X @ Ваши мысли обо всём этом безобразии... Считаю что надо стараться писать как можно более понятный код. Почему стараться? Потому что те библиотеки, которые я назвал появились не на пустом месте до них были другие библиотеки, которые имели плохой код. Во-вторых надо писать только то что нужно не делать код на будущее. Код развивается и постепенно наполняет новыми функциями но в тоже время код подлежит рефакторенгу. Тот же OpenCV переживает уже 4 версию. Каждая версия не совместима с другой потому что отрефакторина убран плохой код убраны подпорки. Правда OpenCV не дотягивает до качественного кода, так как содержит нечитаемый код. В этом плане AForge.NET мне больше нравится (Си#), |
Сообщ.
#14
,
|
|
|
Цитата Jin X @ Ну что это за "красота" такая? Очевидно, что второй вариант на порядок лучше, хз что тебе не нравится Добавлено Цитата Pavia @ Тут видимо конфликт рекомендаций. Должно быть Фигурные скобки опускать никогда нельзя |
Сообщ.
#15
,
|
|
|
Цитата Serafim @ Никогда не говори "никогда". Фигурные скобки опускать никогда нельзя |
Сообщ.
#16
,
|
|
|
Цитата Serafim @ Он лучше, когда основной код занимает больше 1 строки, а здесь какой смысл в этом нагромождении?Очевидно, что второй вариант на порядок лучше Цитата Pavia @ Как же делать if, в котором не нужен else? Прописывать else; тоже не фонтан... Но это противоречит безопасности if без else. |
Сообщ.
#17
,
|
|
|
Цитата Jin X @ Цитата Serafim @ Он лучше, когда основной код занимает больше 1 строки, а здесь какой смысл в этом нагромождении?Очевидно, что второй вариант на порядок лучше Сейчас там 1 строка, завтра может быть 10. Без "нагромождения" нужно будет переписывать. pull-request'ы будут больше и дольше будешь апрувов ждать |
Сообщ.
#18
,
|
|
|
Цитата Jin X @ Он лучше, когда основной код занимает больше 1 строки, а здесь какой смысл в этом нагромождении? Ранний выход из функции проще читается. Я хз как сформулировать своими словами почему именно проще, ты меня в тупик поставил |
Сообщ.
#19
,
|
|
|
D_KEY, намекаешь на то, что все будут пытаться исправить?
Serafim, я понимаю, когда там хотя бы 2-3 строки основного кода. Или если есть большая вероятность, что код будет дописан. Но если предпосылок к расширению кода пока особых нет, чем это лучше? const fetchData = (id) => { if (!id) return; fetch('/data/' + id) } const fetchData = (id) => { if (id) fetch('/data/' + id) } Хоть со {скобками}, хоть без... |
Сообщ.
#20
,
|
|
|
Цитата Jin X @ Цитата villain @ Суть вообще не в этом. Будем считать, что алгоритм достаточно оптимален (это часть кода разложения на простые множители и манипуляции с ними), но есть 2 вот таких варианта реализации как это не углубляйтесь? возможно там вообще деление не нужно Там вообще умножение должно быть, я заменил его на деление для пущего эффекта это не 2 варианта реализации, это 2 разных алгоритма первый лучше - нет внезапного выхода из цикла, 2 условия vs 4 а за while 1: ... if n % i: break отдельный котёл положен |
Сообщ.
#21
,
|
|
|
Цитата villain @ По большому счёту, это один алгоритм всё же. Вот, к примеру здесь тоже 3 разных алгоритма?это не 2 варианта реализации, это 2 разных алгоритма Цитата villain @ Это отсутствие do-while в Python. Можно поменять 2 последние строки местами, как вариант, а перед циклом написать k=1 а за ... отдельный котёл положен |
Сообщ.
#22
,
|
|
|
Цитата Jin X @ По большому счёту, это один алгоритм всё же. Вот, к примеру здесь тоже 3 разных алгоритма? порядок действий разный? значит разные. Цитата Jin X @ Это отсутствие do-while в Python. Можно поменять 2 последние строки местами, как вариант, а перед циклом написать k=1 зачем, если есть вариант без этих костылей? |
Сообщ.
#23
,
|
|
|
Цитата Jin X @ Serafim, я понимаю, когда там хотя бы 2-3 строки основного кода. Или если есть большая вероятность, что код будет дописан. Но если предпосылок к расширению кода пока особых нет, чем это лучше? Как минимум тем, что в первом варианте явно видна сигнатура Promise|null, а во втором - нет. Да и, повторюсь, за опускание фигурных скобок хочется убивать В культурном мире - это как код без отступов - признак плохих манер или неуча за клавиатурой. По крайней мере в JS и некоторых других языках, где уже давно есть codestyle стандарты. |
Сообщ.
#24
,
|
|
|
Цитата Serafim @ Да и, повторюсь, за опускание фигурных скобок хочется убивать В культурном мире - это как код без отступов - признак плохих манер или неуча за клавиатурой. Ох уж мне эти "культурные люди", все-то они возводят в абсолют void doSmthng(){ if(smthngBad1)throw new Exception("Something bad 1"); if(smthngBad2)throw new Exception("Something bad 2"); if(smthngBad3)throw new Exception("Something bad 3"); do(); } Появление фигурных скобок читаемость ухудшит в разы. |
Сообщ.
#25
,
|
|
|
Цитата Астарот @ Появление фигурных скобок читаемость ухудшит в разы. Ага, конечно function doSmthng() { switch (true) { case smthngBad1: throw new Exception("Something bad 1"); case smthngBad2: throw new Exception("Something bad 1"); case smthngBad3: throw new Exception("Something bad 1"); } do(); } Добавлено И то, это потому, что в JS нет нормального паттерн матчинга |
Сообщ.
#26
,
|
|
|
Цитата Serafim @ Ага, конечно И зачем ты три легко читаемые строчки превратил в... это? Да и речь шла про Цитата Serafim @ за опускание фигурных скобок хочется убивать Ну, вот случай, когда опускать их прямо показано |
Сообщ.
#27
,
|
|
|
Цитата Serafim @ Ага, конечно function doSmthng() { switch (true) { case smthngBad1: throw new Exception("Something bad 1"); case smthngBad2: throw new Exception("Something bad 1"); case smthngBad3: throw new Exception("Something bad 1"); } do(); } Вот за такое и правда, хочется взять и у@#$ть. Мне понадобилось несколько секунд, чтобы понять что за муйня такая этот ваш switch(true). |
Сообщ.
#28
,
|
|
|
Цитата applegame @ Вот за такое и правда, хочется взять и у@#$ть. Редкий случай, но я вот тут соглашусь |
Сообщ.
#29
,
|
|
|
Цитата Serafim @ И чем тебе в этом случае поможет "нормальный" паттерн-матчинг? И то, это потому, что в JS нет нормального паттерн матчинга |
Сообщ.
#30
,
|
|
|
Цитата applegame @ И чем тебе в этом случае поможет "нормальный" паттерн-матчинг? Думаю речь тут идет в том числе о том, что в js в case можно методы вызывать, то есть за исключением многословности тот же if получается. |
Сообщ.
#31
,
|
|
|
Цитата Serafim @ И как вы, Serafim, переделаете Астаротский пример, если будет обработка с возвратом?.. (или в Яве такого нет?) Ага, конечно function doSmthng() { switch (true) { case smthngBad1: throw new Exception("Something bad 1"); case smthngBad2: throw new Exception("Something bad 1"); case smthngBad3: throw new Exception("Something bad 1"); } do(); } |
Сообщ.
#32
,
|
|
|
Цитата applegame @ И чем тебе в этом случае поможет "нормальный" паттерн-матчинг? хороший вопрос) в данном случае, кажется, ничем) Цитата Славян @ И как вы, Serafim, переделаете Астаротский пример, если будет обработка с возвратом?.. (или в Яве такого нет?) Имеется ввиду посткондишн? Для этого приватные методы и декораторы, кажется, придумали) |
Сообщ.
#33
,
|
|
|
При чем тут приватные методы и декораторы ? О_о
|
Сообщ.
#34
,
|
|
|
Цитата Астарот @ При чем тут приватные методы и декораторы ? О_о 1) Крупные методы принято делить на более мелкие, в частности твой вариант, в языках с возвращаемым значением в операндах (JS, Python, Ruby), вместо кастуемых (Java, PHP) моет выглядеть следующим образом: // На псевдокоде, а-ля JS или жаба class Some { public function doSmthng() { return checkAbility(a) && checkAbility(b) && checkAbility(c) && do(); // В первой группе языков вернётся значение последнего метода } private function checkAbility(value) { return (bool)value || throw new Exception('...'); } } а ещё можно воспользоваться редукцией в группе "вторых языков" private function checkAbilities(...values): bool { return values.reduce((i, result) -> result ? !i : result, true); // Возвращает, либо тру, либо фолс, если один из аргументов values его содержит } 2) В случае если нужна "обработка с возвратом", что бы это не значило, то можно воспользоваться декоратором, и завраппить ответ. Например, из твоего опыта Астарот, могу привести в пример NotNull аннотацию, которая "враппит" (или контейнеризирует, или декорирует, или вообще это монада ) оригинальное значение. Не она, конечно, а подписчик, не допуская нулевого значения в содержимом. В тоже время Ensure и Verify контракты DbC вполне могут сойти за одну из частных применений декораторов на методах. Выбирай любой способ. Добавлено P.S. Но это всё имеет смысл, когда подобных операций больше трёх. В примере из трёх булевых достаточно: function doSmthng() { if (smthngBad1 || smthngBad2 || smthngBad3) { throw new Exception("Something bad"); } do(); } |
Сообщ.
#35
,
|
|
|
Цитата Serafim @ моет выглядеть следующим образом Какой кошмар Однострочник, в котором еще найди нужную do(), или наоборот нужную проверку, которую ты вынес на сторону, и куда нужно еще посмотреть, что б узнать, что именно оно бросает. Бряки на дебаге тоже ставить одно удовольствие. Б-же, зачем себя так не любить? Цитата Serafim @ а ещё можно Убивайтунг! Вот просто и сразу - ну, не читается же глазом эта билеберда, так зачем? Потому что можешь? Наверное, никогда не пойму этого... Добавлено Цитата Serafim @ В примере из трёх булевых Ага, а потом гадай - какая же из трех "выстрелила" |
Сообщ.
#36
,
|
|
|
Цитата Астарот @ Сильно похоже на ЫГМ - Ынтырпрайз Гойловного Моска. Убивайтунг! Вот просто и сразу - ну, не читается же глазом эта билеберда, так зачем? Потому что можешь? Наверное, никогда не пойму этого... |
Сообщ.
#37
,
|
|
|
Цитата Астарот @ то есть за исключением многословности тот же if получается. Что интересно, в любом случае получится if-else, только на несколько уровней ниже. |
Сообщ.
#38
,
|
|
|
Цитата applegame @ Сильно похоже на ЫГМ - Ынтырпрайз Гойловного Моска. Не знаю, что это, но мне реально страшно - это ж что он может навертеть в действительно не очевидных местах! |
Сообщ.
#39
,
|
|
|
Цитата Астарот @ Вот что это такое - FizzBuzz Enterprise Edition is a no-nonsense implementation of FizzBuzz made by serious businessmen for serious business purposes.Не знаю, что это, но мне реально страшно - это ж что он может навертеть в действительно не очевидных местах! Вот где настоящий ужас |
Сообщ.
#40
,
|
|
|
Не понимаю, что тебе не нравиться, там даже тесты есть
|
Сообщ.
#41
,
|
|
|
Цитата Астарот @ Что значит "даже"? Не понимаю, что тебе не нравиться, там даже тесты есть Это коммерческий код написанный коммерческим программистом в соответствии с высочайшими энтерпрайз стандартами. Там по определению не может не быть тестов. |
Сообщ.
#42
,
|
|
|
switch(true) - это сильно
Больше похоже на обфускацию, а не упрощение кода Цитата Serafim @ Это прикольный выкрутас, конечно (и где-то даже "классический"). Вот только если попадёт в руки джуну, не каждый сообразит, как сие работает.моет выглядеть следующим образом Цитата Serafim @ А вот это особенно. а ещё можно воспользоваться редукцией в группе "вторых языков" Добавлено Цитата Астарот @ Ага, а потом гадай - какая же из трех "выстрелила" function doSmthng() { var i; if (smthngBad1 && (i=1) || smthngBad2 && (i=2) || smthngBad3 && (i=3)) { throw new Exception("Something bad " + i); } doIt(); } function doSmthng() { var i = 1; if (smthngBad1 || ++i && smthngBad2 || ++i && smthngBad3) { throw new Exception("Something bad " + i); } doIt(); } |
Сообщ.
#43
,
|
|
|
А что это switch(true) делает? Я верно понял, что switch разворачивается в пачку if-ов, в каждом из которых проверяется равенство того, что в switch и в case?
|
Сообщ.
#44
,
|
|
|
OpenGL, получается так...
if (true == smthngBad1) {...} if (true == smthngBad2) {...} |
Сообщ.
#45
,
|
|
|
Цитата Jin X @ if (smthngBad1 && (i=1) || smthngBad2 && (i=2) || smthngBad3 && (i=3)) { И потом нарываешься на хитро закопанные грабли в виде смены ключей оптимизации кода, и выясняется... (памяти {$B+}) |
Сообщ.
#46
,
|
|
|
Цитата Vesper @ И потом нарываешься на хитро закопанные грабли в виде смены ключей оптимизации кода, и выясняется А причём тут оптимизация? && и || обязаны выполняться по-порядку, и оптимизатор не имеет права их переставлять. |
Сообщ.
#47
,
|
|
|
Vesper, ну это ж не Delphi, там бы {$B-} был. Ну и это отчасти троллинг примера Серафима, а отчасти... ну мне тоже нравятся такие конструкции и нагромождения всякие (усложнения)
А && имеет более высокий приоритет, чем ||. Добавлено Есть ещё замечательная операция xor (^). Тоже можно побаловаться а-ля if (x ^ y) doSmthng(); Видимо, ^^ не стали делать как раз от греха подальше Добавлено Serafim, вот скажи. Ну нафига фигурные скобки для if (while, for... нужное подчеркнуть), который прописан в одну строку? Собственно, это смежно с if (id) fetch('/data/' + id); |
Сообщ.
#48
,
|
|
|
Цитата Jin X @ Больше похоже на обфускацию, а не упрощение кода Ну не говорить же, что if тут будет лучшим вариантом, только за опускание фигурных скобок всё равно надо отрубить что-нибудь лишнее)) Так что пришлось выкручиваться. С другой стороны, мне кажется нормальным использование switch/case для однотипных условных операторов. Кажется, что для этого он и был предназначен, не?) |
Сообщ.
#49
,
|
|
|
Я понимаю, что какой-нибудь ландырь может по запаре забыть поставить скобки, но при наличии выравнивания этот косяк сразу будет виден...
Добавлено Эх, не успел склеить с предыдущим сообщением Добавлено Цитата Serafim @ ИМХО, он был (хорошее слово) предназначен для проверки 1 переменной на разные значения, а не наоборот Кажется, что для этого он и был предназначен, не?) |
Сообщ.
#50
,
|
|
|
Цитата Jin X @ Serafim, вот скажи. Ну нафига фигурные скобки для if (while, for... нужное подчеркнуть), который прописан в одну строку? Для языков, которые я использую - это общепринятый стандарт, всё равно потом CS поправит код в CI, так что пофигу. Да и вообще, ГОСТ для C/C++, кажется, есть на эту тему |
Сообщ.
#51
,
|
|
|
Цитата Serafim @ Когда больше трёх, ИМХО, лучше использовать не отдельные переменные, а множество, к примеру... Но это всё имеет смысл, когда подобных операций больше трёх. |
Сообщ.
#52
,
|
|
|
Цитата Jin X @ ИМХО, он был (хорошее слово) предназначен для проверки 1 переменной на разные значения, а не наоборот Допускаю, что ты прав. Но это не значит, что обратный случай - плохой. |
Сообщ.
#53
,
|
|
|
Цитата Serafim @ СНиП и СанПиН ГОСТ |
Сообщ.
#54
,
|
|
|
Цитата Jin X @ Когда больше трёх, ИМХО, лучше использовать не отдельные переменные, а множество, к примеру... +1 |
Сообщ.
#55
,
|
|
|
Serafim, кстати, что ты думаешь об if (smthngBad1 && (i=1) || smthngBad2 && (i=2) || smthngBad3 && (i=3)) ?
|
Сообщ.
#56
,
|
|
|
Цитата Jin X @ Видимо, ^^ не стали делать как раз от греха подальше Не от греха подальше, а потому что операция бесмысленна. Главное отличие || от | (&& и &, соответственно), помимо того, что одна - логическая, а вторая - побитовая в том, что первая ещё и ленивая. А вот ^^ ленивой не сделать. Цитата Jin X @ Vesper, ну это ж не Delphi, там бы {$B-} был. Хм, прочитал про это. Какому идиоту вздумалось вводить этот ключ? Это же трындец какой-то. |
Сообщ.
#57
,
|
|
|
Цитата Jin X @ Serafim, кстати, что ты думаешь об if (smthngBad1 && (i=1) || smthngBad2 && (i=2) || smthngBad3 && (i=3)) ? Это печально Сам иногда говнокодю, делая присваивания в условиях, но не до такой степени |
Сообщ.
#58
,
|
|
|
Цитата Serafim @ Сам иногда говнокодю, делая присваивания в условиях, но не до такой степени Эй, а он не безнадежен! |
Сообщ.
#59
,
|
|
|
Цитата OpenGL @ При этом они ещё точки следования вставляют, так что ++ в безопасности.А причём тут оптимизация? && и || обязаны выполняться по-порядку, и оптимизатор не имеет права их переставлять. Цитата Jin X @ Это обычное !=. Зачем? Видимо, ^^ не стали делать как раз от греха подальше |
Сообщ.
#60
,
|
|
|
Цитата OpenGL @ Если под ленивой ты подразумеваешь проверку одного условия из 2-х (если оно true для ||), то отчего ж && не ленивая (при первом false)?Не от греха подальше, а потому что операция бесмысленна. Главное отличие || от | (&& и &, соответственно), помимо того, что одна - логическая, а вторая - побитовая в том, что первая ещё и ленивая. А вот ^^ ленивой не сделать. Цитата Qraizer @ Это обычное !=. Зачем? Цитата Serafim @ Ну ладно... if (smthngBad1 || ++i && smthngBad2 || ++i && smthngBad3)но не до такой степени Как будто бы и не присвоение почти (на всякий случай скажу, что согласен, что это говнокодинг, но выглядит прикольно, поэтому иногда так и подмывает так писать) Добавлено Цитата Qraizer @ Это обычное !=. Зачем? Цитата Jin X @ Хотя нет, не тормознул...Точно. Тормознул чё-т я 5 != 7 = true но 5 ^^ 7 = false Добавлено Если только так извращаться: var x=5, y=7; alert((x&&1) != (y&&1)); // false |
Сообщ.
#61
,
|
|
|
Цитата Jin X @ Если под ленивой ты подразумеваешь проверку одного условия из 2-х (если оно true для ||), то отчего ж && не ленивая (при первом false)? && тоже ленивая уж. Имеется ввиду, что || в моём предложении ты можешь заменить на &&, а | на &. |
Сообщ.
#62
,
|
|
|
Вот, блин!
В JS: 5&&1 = 1, а 1&&5 = 5 5||0 = 5 и 0||5 = 5 (почему одинаково - понятно, но почему не true/false?) Чё за бред? p.s. В сях всё нормально работает: везде выдаёт 1 или true (в т.ч. для 2&&1 и 1&&~1, что ожидаемо). Добавлено Цитата OpenGL @ Что??? Имеется ввиду, что || в моём предложении ты можешь заменить на &&, а | на &. Добавлено OpenGL, ты имеешь в виду, что && и || ленивые в отличие от & и | ? А разве основная ценность в этой ленивости? И это достаточная причина, чтобы не делать ^^ ? Ну реально бывает (редко, но бывает), что нужно сделать (x ^^ y). Можно, конечно, написать (!x != !y), но это тоже не вот прям офигеть как читаемо |
Сообщ.
#63
,
|
|
|
Цитата Jin X @ Ну это не серьёзно. Типы данных разные, и && и &, равно как и || и |, определены для разных типов, для которых есть взаимные касты, тогда как != одна на все типы, и кастов не требуется. Ты же не думаешь, что за типами следить не надо? А то я как-то видал в коде if(a != true), было весело писать багрепорты. Хотя нет, не тормознул... |
Сообщ.
#64
,
|
|
|
Цитата Qraizer @ Надо, но всегда ли есть смысл писать if (x != 0), когда можно написать просто if (x) ?Ты же не думаешь, что за типами следить не надо? А в случае с xor как-то тоже бредово выглядит if ((x && !y) || (!x && y)) и аналогично if ((x!=0 && y==0) || (x==0 && y!=0)). Как ты предлагаешь реализовать xor, чтобы получилось красиво? Добавлено Цитата Jin X @ Или:тоже бредово выглядит bool boolX = x, boolY = y; if (boolX != boolY) {...} if ((bool)x != (bool)y) Добавлено В JS соответственно: var boolX=!!x, boolY=!!y; if (boolX != boolY) {...} |
Сообщ.
#65
,
|
|
|
Цитата Jin X @ OpenGL, ты имеешь в виду, что && и || ленивые в отличие от & и | ? Да. Добавлено Цитата Jin X @ А разве основная ценность в этой ленивости? И это достаточная причина, чтобы не делать ^^ ? Имхо, да. Из-за ленивости ты сможешь написать что-то наподобие if(index < a.len() && a[index] < 42), и замена && на & тут не прокатит. ^^ же ровно с тем же успехом в большинстве случаев заменяется на ^. Цитата Jin X @ Ну реально бывает (редко, но бывает), что нужно сделать (x ^^ y). Когда x и y не булевские, и просто конвертятся неявным кастом? Я в этом случае просто сам сравниваю с нулём. Т.е. как-то if ((x != 0) ^ (y != 0)) пишу. |
Сообщ.
#66
,
|
|
|
Периодически встречаются конструкции вида if x % 1 == 0 или if not 1 % 1 — проверка на целое (python)
Или n = ~~(n/5) — деление нацело (JS) Прикольно, конечно, но в "чистоте" такого кода у меня сомнения... |
Сообщ.
#67
,
|
|
|
Цитата Jin X @ Надо, но всегда ли есть смысл писать if (x != 0), когда можно написать просто if (x) ? Почему нет? В языках без неявного приведения к bool писать != 0 не напрягает совершенно. |
Сообщ.
#68
,
|
|
|
Цитата Jin X @ Вот, блин! В JS: 5&&1 = 1, а 1&&5 = 5 5||0 = 5 и 0||5 = 5 (почему одинаково - понятно, но почему не true/false?) Чё за бред? Я же написал даже, что есть языки, где операнды возвращают значение, а не булев результат: Чистота кода VS оптимизация (сообщение #3766081) пункт номер 1 |
Сообщ.
#69
,
|
|
|
Цитата OpenGL @ Вариант, конечно (тогда можно использовать != – так понятнее).Т.е. как-то if ((x != 0) ^ (y != 0)) пишу. Но это точно лучше, чем if (x ^^ y) (если бы он был)? Добавлено Цитата Serafim @ Сенькс. В Java так же? Я же написал даже, что есть языки, где операнды возвращают значение, а не булев результат |
Сообщ.
#70
,
|
|
|
Цитата Jin X @ Это точно лучше, чем if (x ^^ y) (если бы он был)? Зависит от того, как ты относишься к неявным кастам чисел к bool Я вот за пределами олимпиад стараюсь их избегать, и поэтому даже if (a && b) у меня выглядит как if (a != 0 && b != 0) |
Сообщ.
#71
,
|
|
|
#define XOR(a, b) (bool(a) != bool(b)) . . . if (XOR(x, y)) {...} |
Сообщ.
#72
,
|
|
|
Цитата Jin X @ Сенькс. В Java так же? Я не помню, кажется там каст к булеву. Тут тебе Астарот поможет. А в Ruby и JS - 146% возврат значения. Плюс, в рубях и котлине сами операторы могут возвращать значение, типа: return if (errValue || errValue2) { throw Exception("Whoops!") } else { print("OK") do(); true } |
Сообщ.
#73
,
|
|
|
Цитата Serafim @ C++Плюс, в рубях и котлине сами операторы могут возвращать значение int func(int val) { return val ? (printf("%d ", val), 2) : -1; } int main() { int x; scanf("%d", &x); printf("%d\n", func(x)); return 0; } Добавлено Или так int func(int val) { return val ? ({int x = val*5; printf("%d ", x); 2;}) : -1; } int main() { int x; scanf("%d", &x); printf("%d\n", func(x)); return 0; } |
Сообщ.
#74
,
|
|
|
ммм. А как тема "Чистота кода VS оптимизация" превратилась в соревнование кто по-уродливее код написать может?
|
Сообщ.
#75
,
|
|
|
Это значит, что любой оператор (хотя в котлине вроде только if):
verifyItems = (...args) => (i or throw Error "asd" for i of args).length Применение для каждого элемента args функции, которая в случае элемента, который равен false вернёт ошибку, в остальных случаях значение аккумулируется и от него берётся length, т.е. количество элементов в результате (этот ваш незамысловатый i++ в if условии). А вот даже можно собрать это всё |
Сообщ.
#76
,
|
|
|
Цитата Jin X @ Как ты предлагаешь реализовать xor, чтобы получилось красиво? if(!!x != !!y) /* ... */ |
Сообщ.
#77
,
|
|
|
Qraizer, ага. С одним ! не так красиво?
|
Сообщ.
#78
,
|
|
|
Конечно, нет. Алгоритм-то другой.
|
Сообщ.
#79
,
|
|
|
А я, Serafim, вообще стараюсь избегать фигурных, если позволительно, a'la:
if( ... ) A = B, func1( ... ), p = func2(...); else C = D, ...; |
Сообщ.
#80
,
|
|
|
Славян, ну это уже борщ, ИМХО
|
Сообщ.
#81
,
|
|
|
Цитата Славян @ А я, Serafim, вообще стараюсь избегать фигурных, если позволительно, a'la: А я джунов своих по рукам за это бью) |
Сообщ.
#82
,
|
|
|
Бедные джуны.
|
Сообщ.
#83
,
|
|
|
Цитата Serafim @ Цитата Славян @ А я, Serafim, вообще стараюсь избегать фигурных, если позволительно, a'la: А я джунов своих по рукам за это бью) А тот код, что ты выше приводил, заставляешь писать? |
Сообщ.
#84
,
|
|
|
Зато QA меньше проблем с "внезапно появившимися багами из ниоткуда"
Добавлено Цитата D_KEY @ А тот код, что ты выше приводил, заставляешь писать? Допустим повышенный Complexity, как в примере выше, обычный анализатор сам подсветит, сложнее с Protected Variations и Cohesion - тут надо самому думать как не свалиться в рефакторинг) |
Сообщ.
#85
,
|
|
|
Цитата Jin X @ А && имеет более высокий приоритет, чем ||. Приоритет приоритетом, но флаг complete boolean eval означает вычислить все части булева выражения, даже если они уже не влияют на итоговый результат. Пример был вида "if (a<100) or add1(a) then..." где add1 - функция с сайд-эффектом, возвращающая boolean, и при B+ переменная а всегда увеличивалась, а при В- только если (а<100) было ложным. Вот мало ли кто захочет зачем-то поменять эту нас ройку, тем боле если в заголовке где-то проскочит, а особенно если это что-то фиг-отладишь типа буста. Вот надо им было, а ты теперь страдай. Цитата OpenGL @ Хм, прочитал про это. Какому идиоту вздумалось вводить этот ключ? Это же трындец какой-то. Сюрприз, да |
Сообщ.
#86
,
|
|
|
Цитата Vesper @ Приоритет приоритетом, но флаг complete boolean eval означает вычислить все части булева выражения, даже если они уже не влияют на итоговый результат. Цитата Vesper @ Ну вообще, по умолчанию она отключена. Но я, например, если пишу код, в котором эта настройка (или какая-либо другая) важна, прописываю её в заголовке и проблем нет.Сюрприз, да Там помимо этой настройки есть ещё R, Q, Z и пр., которые тоже могут неслабо влиять на результат. Надо просто знать об этом и проставлять нужные опции. В IDE есть комбинация Ctrl+O+O, которая позволяет быстро увидеть текущие настройки и зафиксировать их. Добавлено В целом же, довольно неплохо иметь привычку всовывать в начало исходников строчку вида {$A8,Z1,O+,Q-,R-,B-} А в главный модуль (program) можно ещё и {$SetPEFlags IMAGE_FILE_RELOCS_STRIPPED} (при подключенном модуле Windows, ну или {$SetPEFlags 1}) вставлять для удаления фиксапов из EXE-шника (которые там нафиг не нужны). Только в DLL такого не надо делать |
Сообщ.
#87
,
|
|
|
Неужели кто-то ещё пишет на Delphi?
|
Сообщ.
#88
,
|
|
|
D_KEY, нет, конечно, никто не пишет.
Embarcadero чисто по загону новые версии выпускает. Для прикола, тупо поржать |
Сообщ.
#90
,
|
|
|
Цитата Vesper @ Вот мало ли кто захочет зачем-то поменять эту нас ройку, тем боле если в заголовке где-то проскочит, а особенно если это что-то фиг-отладишь типа буста. В плюсовых компиляторах тоже такая настройка имеется? Что-то сильно сомневаюсь. Максимум, что ты сделаешь в плюсах - перегрузишь логические операторы для своих типов. И вообще, можно пруф того, что это бывает не только в дельфи? |
Сообщ.
#91
,
|
|
|
Цитата Qraizer @ Чтобы ASLR работал, нужно либо включить соответствующие опции в PE-заголовке (при компиляции, например). Либо прописать эти опции в реестре для конкретного файла.чем напрочь запрещаем ASLR. Но в целом ты прав, конечно. Добавлено Не углублялся в эту тему раньше. Ну тогда вместо отключения фиксапов можно включать ASLR и DEP (ну или просто DEP хотя бы): {$APPTYPE CONSOLE} uses Windows, SysUtils; const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = $40; // ASLR, {$DYNAMICBASE ON} in Delphi 2007+ IMAGE_DLLCHARACTERISTICS_NX_COMPAT = $100; // DEP {$SetPEOptFlags IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE or IMAGE_DLLCHARACTERISTICS_NX_COMPAT} // {$SetPEOptFlags $140}, works on Delphi 6+ (and maybe earlier) // http://qaru.site/questions/663368/how-can-i-enable-depnx-and-aslr-on-a-delphi-2006-or-earlier-executable // https://habrahabr.ru/company/eset/blog/206244/ const R: Byte = $C3; begin WriteLn(IntToHex(DWord(@IntToHex), 8)); try TProcedure(@R); WriteLn('DEP is OFF :('); except WriteLn('DEP is ON :)'); end; end. |
Сообщ.
#92
,
|
|
|
Без reloc-ов по-любому ASLR не заработает. Но тут как бы палка о двух концах. Во время отладки стрипать их даже полезно, ибо бряки, не привязанные к строкам кода, а поставленные, скажем, на конкретные ассемблерные инструкции, что нередко бывает нужно для либ без сыров, при активном ASLR слетают токатак. Но вот в релизе я удалять их всё-таки бы не советовал.
|
Сообщ.
#93
,
|
|
|
Цитата Qraizer @ Да это понятное дело.Без reloc-ов по-любому ASLR не заработает. Цитата Qraizer @ Можно так:Во время отладки стрипать их даже полезно {$IFDEF DEBUG} {$SetPEFlags IMAGE_FILE_RELOCS_STRIPPED} {$ELSE} {$SetPEOptFlags IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE} {$ENDIF} {$SetPEOptFlags IMAGE_DLLCHARACTERISTICS_NX_COMPAT} |
Сообщ.
#94
,
|
|
|
Кстати, кто подскажет, что это за прога (которая показывает заголовок PE в таком виде)?
|
Сообщ.
#95
,
|
|
|
Цитата Serafim @ Крупные методы принято делить на более мелкие, в частности твой вариант, в языках с возвращаемым значением в операндах (JS, Python, Ruby), вместо кастуемых (Java, PHP) моет выглядеть следующим образом: … А в нормальных следующим: doSomethingClever :: Int -> String -> String doSomethingClever id name = show id ++ " => " ++ name tryToDoSomethingClever :: Maybe Int -> Result String tryToDoSomethingClever idParam = do id <- getId idParam item <- getItem id name <- getName item return (doSomethingClever id name) Добавлено Цитата Jin X @ Embarcadero чисто по загону новые версии выпускает. Для прикола, тупо порубить хоть чуть-чуть бабла на легаси-проектах Ага. |
Сообщ.
#96
,
|
|
|
Цитата korvin @ А в нормальных следующим: Оуоу, палехче))) P.S. А это разве не первый вариант? Возвращается же в конце концов функция (точнее композиция функций). Только указанная в качестве первого операнда, если, конечно не использовался оператор "$", тогда вернётся последующий аргумент. P.P.S. Хотя... Кажется это ещё один вариант: 1) C, Java, PHP: "res = a || b" Результат: res = bool 2) JS, Ruby, Python: "res = a || b" Результат: res = a (если он тру) или b 3) Haskell: "res = a || b" Результат: функция "||" от a и b (я довольно плохо плохо знаю Haskell, так что поправь, если ошибаюсь) |
Сообщ.
#97
,
|
|
|
Цитата Serafim @ Результат: функция "||" от a и b Что? {- tryToDoSomethingClever :: Maybe Int -> Result String tryToDoSomethingClever idParam = do id <- getId idParam item <- getItem id name <- getName item return (doSomethingClever id name) tryToDoSomethingClever :: Maybe Int -> Result String tryToDoSomethingClever idParam = getId idParam >>= (\id -> getItem id >>= (\item -> getName item >>= (\name -> return (doSomethingClever id name)))) -} tryToDoSomethingClever :: Maybe Int -> Result String tryToDoSomethingClever idParam = case getId idParam of Err msg -> Err msg Ok id -> case getItem id of Err msg -> Err msg Ok item -> case getName item of Err msg -> Err msg Ok name -> Ok (doSomethingClever id name) https://ideone.com/f4Bzen |
Сообщ.
#98
,
|
|
|
Цитата Serafim @ Что значит bool? true если a, иначе true если b, иначе false. При проверке условия вместо возврата результата сразу производится переход к нужной ветке.1) C, Java, PHP: "res = a || b" Результат: res = bool На самом деле вычисление результата тоже производится переходами. То есть фактически в C res = a || b означает res = (a || b)? true: false Цитата Serafim @ В Python надо писать res = a or b. В остальном почти верно. При вычислении результата, сразу после определения значения выражения производится переход на точку сохранения результата. 2) JS, Ruby, Python: "res = a || b" Результат: res = a (если он тру) или b |
Сообщ.
#99
,
|
|
|
Цитата amk @ Что значит bool? Это означает, что там может находиться либо true, либо false и никак иначе. |
Сообщ.
#100
,
|
|
|
Цитата Serafim @ Но не указано, что если по `a` можно определить ответ, то `b` не анализируется Это означает, что там может находиться либо true, либо false и никак иначе. |
Сообщ.
#101
,
|
|
|
amk, я думаю, это не сложно определить эмпирически
|
Сообщ.
#102
,
|
|
|
Цитата amk @ Но не указано, что если по `a` можно определить ответ, то `b` не анализируется Да ладно? Ты уверен? |
Сообщ.
#103
,
|
|
|
Уверен. В C это описано стандартом.
Так же и в C++, если переменные не являются пользовательскими типами. Но в таком случае не может быть уверенности даже в результирующем значении. Пользовательский operator||() вовсе не обязан возвращать bool |
Сообщ.
#104
,
|
|
|
Цитата Serafim @ Да ладно? Ты уверен? Так практически везде же. |
Сообщ.
#105
,
|
|
|
Простите, я табличку сарказма потерял
|