Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Holy Wars > Чистота кода VS оптимизация


Автор: Jin X 06.04.18, 11:24
Много статей развелось про чистоту кода (на основе книги Р.Мартина и не только). В целом концепция, конечно, хорошая.
Но бывают какие-то прямо абсурдные, ИМХО, рекомендации.
Вот к примеру тут:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // ????
    const fetchData = (id) => {
      if (id) {
        fetch('/data/' + id)
      }
    }
    // ????
    const fetchData = (id) => {
      if (!id) {
        return
      }
      fetch('/data/' + id)
    }
Ну что это за "красота" такая?

И вот такие слова в конце статьи:
Цитата
«Погодите! А как насчет изменения производительности?». Мне это безразлично. Правда. Разве что есть реальная проблема, когда приложение становится медленнее, чем ожидалось.

С таким мышлением закон Вирта совершенно не кажется "шуткой":
Цитата
Программы становятся медленнее куда шустрее, чем компьютеры становятся быстрее

Далее, второй момент. Более "тонкий", скажем так.
Example1 (кусочек кода):
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    . . .
      while i*i <= n:
        k = 1
        while n % i == 0:
          k += 2
          n //= i
        result /= k
        i += 1
    . . .

Example2 (кусочек кода):
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    . . .
      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++ :)).

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

Ваши мысли обо всём этом безобразии... :whistle:

Автор: JoeUser 06.04.18, 12:02
Не читай плохих статей! :lol: Создавать Elephantware имеет смысл только тогда, когда ты в пожизненной разработке проекта, и тебе оплачивают не качество, а количество доработок.

Автор: villain 06.04.18, 12:21
Цитата Jin X @
Не углубляйтесь в суть алгоритма, это неважно.

как это не углубляйтесь? возможно там вообще деление не нужно

Автор: Jin X 06.04.18, 12:46
Цитата villain @
как это не углубляйтесь? возможно там вообще деление не нужно
Суть вообще не в этом. Будем считать, что алгоритм достаточно оптимален (это часть кода разложения на простые множители и манипуляции с ними), но есть 2 вот таких варианта реализации :)
Там вообще умножение должно быть, я заменил его на деление для пущего эффекта :D

Автор: Jin X 06.04.18, 13:12
Цитата JoeUser @
Создавать Elephantware имеет смысл только тогда, когда ты в пожизненной разработке проекта, и тебе оплачивают не качество, а количество доработок.
Не, ну понятно, что создавать класс в 3 поколения с 10 методами в каждом там, когда нужно сделать просто min(x,y) - это бред. Речь идёт именно о чистоте кода, а не о заделе на будущее. Т.е. о понятности кода тебе и людям с возможностью лёгкой модификации.
Реально ли (почти) всегда нужно писать одно действие-одна функция и выстраивать 5-этажные вызовы там, где можно было бы обойтись одной функцией?
Реально ли (почти) всегда стоит заменять:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // ????
    people
      .filter(person => person.age > 10 && person.firstName.length > 2 && person.lastName.length > 4)
на:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // ????
    people
      .filter(person => person.age > 10)
      .filter(person => person.firstName.length > 2)
      .filter(person => person.lastName.length > 4)
ради лучшей читабельности? И т.д.

Автор: applegame 06.04.18, 13:19
Цитата Jin X @
Реально ли (почти) всегда стоит заменять:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // ????
    people
      .filter(person => person.age > 10 && person.firstName.length > 2 && person.lastName.length > 4)
на:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // ????
    people
      .filter(person => person.age > 10)
      .filter(person => person.firstName.length > 2)
      .filter(person => person.lastName.length > 4)
ради лучшей читабельности? И т.д.

Можно еще вот так
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // ????
    people.filter(
      person =>
        person.age > 10 &&
        person.firstName.length > 2 &&
        person.lastName.length > 4
    )

Автор: D_KEY 06.04.18, 13:58
Цитата Jin X @
Ну что это за "красота" такая?

Думаю, что тут имелся в виду принцип о размещении реакции на нарушения предусловий и обработки "внешних" ошибок в начале функций/методов.
Как правило это действительно улучшает читаемость, поскольку дальнейшеая логика становится более простой.

Добавлено
Цитата Jin X @
И вот такие слова в конце статьи:
Цитата
«Погодите! А как насчет изменения производительности?». Мне это безразлично. Правда. Разве что есть реальная проблема, когда приложение становится медленнее, чем ожидалось.

С таким мышлением закон Вирта совершенно не кажется "шуткой":
Цитата
Программы становятся медленнее куда шустрее, чем компьютеры становятся быстрее

Ну портить код без оснований для улучшения производительности действительно не стоит. И вполне допустимо улучшить его там, где скорость не критична.

Добавлено
Цитата Jin X @
Но представим, что мы пишем библиотеку и не знаем как она будет использоваться.

Совсем не знаем? Тогда зачем пишем? :D

Добавлено
Цитата Jin X @
Реально ли (почти) всегда стоит заменять:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // ????
    people
      .filter(person => person.age > 10 && person.firstName.length > 2 && person.lastName.length > 4)
на:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // ????
    people
      .filter(person => person.age > 10)
      .filter(person => person.firstName.length > 2)
      .filter(person => person.lastName.length > 4)
ради лучшей читабельности? И т.д.

А здесь лучше читабельность? :D

Автор: amk 06.04.18, 14:27
Цитата Jin X @
Второй вариант чуть более сложный для понимания (спасибо разработчикам Python'а за отсутствие do-while/repeat-until), но и чуть более оптимальный по скорости
Какой же он оптимальный? Тут в каждом цикле два деления, когда можно обойтись одним.

Автор: Jin X 06.04.18, 15:14
Цитата amk @
Тут в каждом цикле два деления
2 деления во внешне цикле, 2 во внутреннем. Во втором примере при невыполнении условия внешнего цикла деление одно (в самом этом условии).
Цитата amk @
когда можно обойтись одним.
Мне вот даже интересно, как тут можно обойтись одним делением? :)

Добавлено
А, ну вот вижу вроде в питоне есть функция divmod, но это для внешнего цикла только... а дальше?

Добавлено
Хотя нифига, divmod, как оказалось, работает медленнее (даже медленнее 2 вызовов: % и //)

Добавлено
Причём, я сейчас замерил скорость Example1 и Example2 (причём, с умножением, а не с делением result'а). Разница более 30%, о как!

Автор: amk 06.04.18, 16:05
Цитата Jin X @
Хотя нифига, divmod, как оказалось, работает медленнее (даже медленнее 2 вызовов: % и //)
Т ак ты же вроде просил не обращать внимания на язык. В Си оптимизатор заменяет пару % / на одно деление. Вынесение одной из этих двух операций может сломать оптимизацию.

В любом случае нет смысла огород городить из-за всего одного сэкономленного деления. Судя по всему, это деление мало на что влияет.

Автор: Jin X 06.04.18, 16:07
Цитата D_KEY @
Совсем не знаем? Тогда зачем пишем?
Вот написал кто-то функцию power. Сразу понятно, где она может использоваться? :)

Добавлено
Цитата amk @
Т ак ты же вроде просил не обращать внимания на язык.
:lol:
Ну код же не на Си :)
Но в любом случае % во внутреннем цикле и result /= k ты одним делением не сделаешь.

Добавлено
Но мы от сути вопроса отошли...

Автор: D_KEY 06.04.18, 16:55
Цитата Jin X @
Цитата D_KEY @
Совсем не знаем? Тогда зачем пишем?
Вот написал кто-то функцию power. Сразу понятно, где она может использоваться? :)

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

Автор: Pavia 06.04.18, 17:04
Цитата Jin X @
parseOne('code_1','js',false)preloadCodeButtons('1');Ну что это за "красота" такая?

Тут видимо конфликт рекомендаций. Должно быть
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    const fetchData = (id) => {
      if (!id)  return;
      fetch('/data/' + id)
    }


Но это противоречит безопасности if без else. Да и return по серёдке кода.

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    . . .
      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 мне больше нравится (Си#),

Автор: Serafim 07.04.18, 00:40
Цитата Jin X @
Ну что это за "красота" такая?

Очевидно, что второй вариант на порядок лучше, хз что тебе не нравится :-?

Добавлено
Цитата Pavia @
Тут видимо конфликт рекомендаций. Должно быть

Фигурные скобки опускать никогда нельзя :yes:

Автор: applegame 07.04.18, 05:37
Цитата Serafim @
Фигурные скобки опускать никогда нельзя
Никогда не говори "никогда". :yes:

Автор: Jin X 08.04.18, 06:56
Цитата Serafim @
Очевидно, что второй вариант на порядок лучше
Он лучше, когда основной код занимает больше 1 строки, а здесь какой смысл в этом нагромождении?

Цитата Pavia @
Но это противоречит безопасности if без else.
Как же делать if, в котором не нужен else? Прописывать else; тоже не фонтан...

Автор: D_KEY 08.04.18, 08:21
Цитата Jin X @
Цитата Serafim @
Очевидно, что второй вариант на порядок лучше
Он лучше, когда основной код занимает больше 1 строки, а здесь какой смысл в этом нагромождении?

Сейчас там 1 строка, завтра может быть 10. Без "нагромождения" нужно будет переписывать.
pull-request'ы будут больше и дольше будешь апрувов ждать :D

Автор: Serafim 08.04.18, 11:29
Цитата Jin X @
Он лучше, когда основной код занимает больше 1 строки, а здесь какой смысл в этом нагромождении?

Ранний выход из функции проще читается. Я хз как сформулировать своими словами почему именно проще, ты меня в тупик поставил :-?

Автор: Jin X 08.04.18, 14:33
D_KEY, намекаешь на то, что все будут пытаться исправить?

Serafim, я понимаю, когда там хотя бы 2-3 строки основного кода. Или если есть большая вероятность, что код будет дописан. Но если предпосылок к расширению кода пока особых нет, чем это лучше?
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    const fetchData = (id) => {
      if (!id) return;
      fetch('/data/' + id)
    }
против
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    const fetchData = (id) => {
      if (id) fetch('/data/' + id)
    }

Хоть со {скобками}, хоть без... :)

Автор: villain 09.04.18, 05:29
Цитата Jin X @
Цитата villain @
как это не углубляйтесь? возможно там вообще деление не нужно
Суть вообще не в этом. Будем считать, что алгоритм достаточно оптимален (это часть кода разложения на простые множители и манипуляции с ними), но есть 2 вот таких варианта реализации :)
Там вообще умножение должно быть, я заменил его на деление для пущего эффекта :D

:facepalm:
это не 2 варианта реализации, это 2 разных алгоритма
первый лучше - нет внезапного выхода из цикла, 2 условия vs 4
а за
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    while 1:
       ...
       if n % i: break

отдельный котёл положен >:(

Автор: Jin X 09.04.18, 11:12
Цитата villain @
это не 2 варианта реализации, это 2 разных алгоритма
По большому счёту, это один алгоритм всё же. Вот, к примеру здесь тоже 3 разных алгоритма?

Цитата villain @
а за
...
отдельный котёл положен
Это отсутствие do-while в Python. Можно поменять 2 последние строки местами, как вариант, а перед циклом написать k=1 :)

Автор: villain 09.04.18, 12:44
Цитата Jin X @
По большому счёту, это один алгоритм всё же. Вот, к примеру здесь тоже 3 разных алгоритма?

порядок действий разный? значит разные.

Цитата Jin X @
Это отсутствие do-while в Python. Можно поменять 2 последние строки местами, как вариант, а перед циклом написать k=1 :)

зачем, если есть вариант без этих костылей?

Автор: Serafim 09.04.18, 13:13
Цитата Jin X @
Serafim, я понимаю, когда там хотя бы 2-3 строки основного кода. Или если есть большая вероятность, что код будет дописан. Но если предпосылок к расширению кода пока особых нет, чем это лучше?

Как минимум тем, что в первом варианте явно видна сигнатура Promise|null, а во втором - нет.

Да и, повторюсь, за опускание фигурных скобок хочется убивать :D В культурном мире - это как код без отступов - признак плохих манер или неуча за клавиатурой. По крайней мере в JS и некоторых других языках, где уже давно есть codestyle стандарты.

Автор: Астарот 09.04.18, 14:33
Цитата Serafim @
Да и, повторюсь, за опускание фигурных скобок хочется убивать :D В культурном мире - это как код без отступов - признак плохих манер или неуча за клавиатурой.

Ох уж мне эти "культурные люди", все-то они возводят в абсолют :)
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    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();
    }

Появление фигурных скобок читаемость ухудшит в разы.

Автор: Serafim 09.04.18, 14:44
Цитата Астарот @
Появление фигурных скобок читаемость ухудшит в разы.

Ага, конечно
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    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 нет нормального паттерн матчинга

Автор: Астарот 09.04.18, 15:25
Цитата Serafim @

Ага, конечно

И зачем ты три легко читаемые строчки превратил в... это? :D Да и речь шла про
Цитата Serafim @
за опускание фигурных скобок хочется убивать

Ну, вот случай, когда опускать их прямо показано :thanks:

Автор: applegame 09.04.18, 15:38
Цитата Serafim @
Ага, конечно
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    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).

Автор: Астарот 09.04.18, 15:39
Цитата applegame @
Вот за такое и правда, хочется взять и у@#$ть.

Редкий случай, но я вот тут соглашусь :yes:

Автор: applegame 09.04.18, 15:42
Цитата Serafim @
И то, это потому, что в JS нет нормального паттерн матчинга
И чем тебе в этом случае поможет "нормальный" паттерн-матчинг?

Автор: Астарот 09.04.18, 15:46
Цитата applegame @
И чем тебе в этом случае поможет "нормальный" паттерн-матчинг?

Думаю речь тут идет в том числе о том, что в js в case можно методы вызывать, то есть за исключением многословности тот же if получается.

Автор: Славян 09.04.18, 16:21
Цитата Serafim @
Ага, конечно
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    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();
    }
И как вы, Serafim, переделаете Астаротский пример, если будет обработка с возвратом?.. (или в Яве такого нет?)

Автор: Serafim 09.04.18, 21:30
Цитата applegame @
И чем тебе в этом случае поможет "нормальный" паттерн-матчинг?

хороший вопрос) в данном случае, кажется, ничем)

Цитата Славян @
И как вы, Serafim, переделаете Астаротский пример, если будет обработка с возвратом?.. (или в Яве такого нет?)

Имеется ввиду посткондишн? Для этого приватные методы и декораторы, кажется, придумали)

Автор: Астарот 09.04.18, 21:49
При чем тут приватные методы и декораторы ? О_о

Автор: Serafim 10.04.18, 01:53
Цитата Астарот @
При чем тут приватные методы и декораторы ? О_о

1) Крупные методы принято делить на более мелкие, в частности твой вариант, в языках с возвращаемым значением в операндах (JS, Python, Ruby), вместо кастуемых (Java, PHP) моет выглядеть следующим образом:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // На псевдокоде, а-ля JS или жаба
    class Some {
        public function doSmthng() {
            return checkAbility(a) && checkAbility(b) && checkAbility(c) && do(); // В первой группе языков вернётся значение последнего метода
        }
     
        private function checkAbility(value) {
            return (bool)value || throw new Exception('...');
        }
    }


а ещё можно воспользоваться редукцией в группе "вторых языков" :)

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    private function checkAbilities(...values): bool {
        return values.reduce((i, result) -> result ? !i : result, true); // Возвращает, либо тру, либо фолс, если один из аргументов values его содержит
    }



2) В случае если нужна "обработка с возвратом", что бы это не значило, то можно воспользоваться декоратором, и завраппить ответ. Например, из твоего опыта Астарот, могу привести в пример NotNull аннотацию, которая "враппит" (или контейнеризирует, или декорирует, или вообще это монада :D ) оригинальное значение. Не она, конечно, а подписчик, не допуская нулевого значения в содержимом. В тоже время Ensure и Verify контракты DbC вполне могут сойти за одну из частных применений декораторов на методах. Выбирай любой способ.

Добавлено
P.S. Но это всё имеет смысл, когда подобных операций больше трёх. В примере из трёх булевых достаточно:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    function doSmthng() {
        if (smthngBad1 || smthngBad2 || smthngBad3) {
            throw new Exception("Something bad");
        }
     
        do();
    }

Автор: Астарот 10.04.18, 06:25
Цитата Serafim @
моет выглядеть следующим образом

Какой кошмар :-? Однострочник, в котором еще найди нужную do(), или наоборот нужную проверку, которую ты вынес на сторону, и куда нужно еще посмотреть, что б узнать, что именно оно бросает. Бряки на дебаге тоже ставить одно удовольствие. Б-же, зачем себя так не любить?

Цитата Serafim @
а ещё можно

Убивайтунг! Вот просто и сразу - ну, не читается же глазом эта билеберда, так зачем? Потому что можешь? Наверное, никогда не пойму этого...

Добавлено
Цитата Serafim @
В примере из трёх булевых

Ага, а потом гадай - какая же из трех "выстрелила" :D

Автор: applegame 10.04.18, 06:30
Цитата Астарот @
Убивайтунг! Вот просто и сразу - ну, не читается же глазом эта билеберда, так зачем? Потому что можешь? Наверное, никогда не пойму этого...
Сильно похоже на ЫГМ - Ынтырпрайз Гойловного Моска.

Автор: Vesper 10.04.18, 06:36
Цитата Астарот @
то есть за исключением многословности тот же if получается.

Что интересно, в любом случае получится if-else, только на несколько уровней ниже.

Автор: Астарот 10.04.18, 07:02
Цитата applegame @
Сильно похоже на ЫГМ - Ынтырпрайз Гойловного Моска.

Не знаю, что это, но мне реально страшно - это ж что он может навертеть в действительно не очевидных местах! :unsure:

Автор: applegame 10.04.18, 07:40
Цитата Астарот @
Не знаю, что это, но мне реально страшно - это ж что он может навертеть в действительно не очевидных местах! :unsure:
Вот что это такое - FizzBuzz Enterprise Edition is a no-nonsense implementation of FizzBuzz made by serious businessmen for serious business purposes.
Вот где настоящий ужас :lol:

Автор: Астарот 10.04.18, 07:58
Не понимаю, что тебе не нравиться, там даже тесты есть :D

Автор: applegame 10.04.18, 08:01
Цитата Астарот @
Не понимаю, что тебе не нравиться, там даже тесты есть :D
Что значит "даже"? >:(
Это коммерческий код написанный коммерческим программистом в соответствии с высочайшими энтерпрайз стандартами. Там по определению не может не быть тестов.

Автор: Jin X 10.04.18, 10:29
switch(true) - это сильно :)
Больше похоже на обфускацию, а не упрощение кода :lol:

Цитата Serafim @
моет выглядеть следующим образом
Это прикольный выкрутас, конечно (и где-то даже "классический"). Вот только если попадёт в руки джуну, не каждый сообразит, как сие работает.
Цитата Serafim @
а ещё можно воспользоваться редукцией в группе "вторых языков"
А вот это особенно.

Добавлено
Цитата Астарот @
Ага, а потом гадай - какая же из трех "выстрелила"

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    function doSmthng() {
        var i;
        if (smthngBad1 && (i=1) || smthngBad2 && (i=2) || smthngBad3 && (i=3)) {
            throw new Exception("Something bad " + i);
        }
     
        doIt();
    }
Или...
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    function doSmthng() {
        var i = 1;
        if (smthngBad1 || ++i && smthngBad2 || ++i && smthngBad3) {
            throw new Exception("Something bad " + i);
        }
     
        doIt();
    }
:lol:

Автор: OpenGL 10.04.18, 10:55
А что это switch(true) делает? Я верно понял, что switch разворачивается в пачку if-ов, в каждом из которых проверяется равенство того, что в switch и в case?

Автор: Jin X 10.04.18, 11:01
OpenGL, получается так...
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    if (true == smthngBad1) {...}
    if (true == smthngBad2) {...}

Автор: Vesper 10.04.18, 11:11
Цитата Jin X @
if (smthngBad1 && (i=1) || smthngBad2 && (i=2) || smthngBad3 && (i=3)) {

И потом нарываешься на хитро закопанные грабли в виде смены ключей оптимизации кода, и выясняется... (памяти {$B+})

Автор: OpenGL 10.04.18, 11:18
Цитата Vesper @
И потом нарываешься на хитро закопанные грабли в виде смены ключей оптимизации кода, и выясняется

А причём тут оптимизация? && и || обязаны выполняться по-порядку, и оптимизатор не имеет права их переставлять.

Автор: Jin X 10.04.18, 11:34
Vesper, ну это ж не Delphi, там бы {$B-} был. Ну и это отчасти троллинг примера Серафима, а отчасти... ну мне тоже нравятся такие конструкции и нагромождения всякие (усложнения) :)
А && имеет более высокий приоритет, чем ||.

Добавлено
Есть ещё замечательная операция xor (^).
Тоже можно побаловаться а-ля if (x ^ y) doSmthng();
Видимо, ^^ не стали делать как раз от греха подальше :D

Добавлено
Serafim, вот скажи. Ну нафига фигурные скобки для if (while, for... нужное подчеркнуть), который прописан в одну строку?
Собственно, это смежно с if (id) fetch('/data/' + id);

Автор: Serafim 10.04.18, 11:40
Цитата Jin X @
Больше похоже на обфускацию, а не упрощение кода

Ну не говорить же, что if тут будет лучшим вариантом, только за опускание фигурных скобок всё равно надо отрубить что-нибудь лишнее)) Так что пришлось выкручиваться.

С другой стороны, мне кажется нормальным использование switch/case для однотипных условных операторов. Кажется, что для этого он и был предназначен, не?)

Автор: Jin X 10.04.18, 11:41
Я понимаю, что какой-нибудь ландырь может по запаре забыть поставить скобки, но при наличии выравнивания этот косяк сразу будет виден...

Добавлено
Эх, не успел склеить с предыдущим сообщением <_<

Добавлено
Цитата Serafim @
Кажется, что для этого он и был предназначен, не?)
ИМХО, он был (хорошее слово) предназначен для проверки 1 переменной на разные значения, а не наоборот :)

Автор: Serafim 10.04.18, 11:43
Цитата Jin X @
Serafim, вот скажи. Ну нафига фигурные скобки для if (while, for... нужное подчеркнуть), который прописан в одну строку?

Для языков, которые я использую - это общепринятый стандарт, всё равно потом CS поправит код в CI, так что пофигу.

Да и вообще, ГОСТ для C/C++, кажется, есть на эту тему :whistle:

Автор: Jin X 10.04.18, 11:46
Цитата Serafim @
Но это всё имеет смысл, когда подобных операций больше трёх.
Когда больше трёх, ИМХО, лучше использовать не отдельные переменные, а множество, к примеру...

Автор: Serafim 10.04.18, 11:46
Цитата Jin X @
ИМХО, он был (хорошее слово) предназначен для проверки 1 переменной на разные значения, а не наоборот

Допускаю, что ты прав. Но это не значит, что обратный случай - плохой.

Автор: Jin X 10.04.18, 11:46
Цитата Serafim @
ГОСТ
СНиП и СанПиН :)

Автор: Serafim 10.04.18, 11:47
Цитата Jin X @
Когда больше трёх, ИМХО, лучше использовать не отдельные переменные, а множество, к примеру...

+1

Автор: Jin X 10.04.18, 11:54
Serafim, кстати, что ты думаешь об if (smthngBad1 && (i=1) || smthngBad2 && (i=2) || smthngBad3 && (i=3)) ? :P

Автор: OpenGL 10.04.18, 11:57
Цитата Jin X @
Видимо, ^^ не стали делать как раз от греха подальше

Не от греха подальше, а потому что операция бесмысленна. Главное отличие || от | (&& и &, соответственно), помимо того, что одна - логическая, а вторая - побитовая в том, что первая ещё и ленивая. А вот ^^ ленивой не сделать.

Цитата Jin X @
Vesper, ну это ж не Delphi, там бы {$B-} был.

Хм, прочитал про это. Какому идиоту вздумалось вводить этот ключ? :unsure: Это же трындец какой-то.

Автор: Serafim 10.04.18, 11:58
Цитата Jin X @
Serafim, кстати, что ты думаешь об if (smthngBad1 && (i=1) || smthngBad2 && (i=2) || smthngBad3 && (i=3)) ?

Это печально :) Сам иногда говнокодю, делая присваивания в условиях, но не до такой степени :D

Автор: Астарот 10.04.18, 12:01
Цитата Serafim @
Сам иногда говнокодю, делая присваивания в условиях, но не до такой степени :D

Эй, а он не безнадежен! :D

Автор: Qraizer 10.04.18, 12:06
Цитата OpenGL @
А причём тут оптимизация? && и || обязаны выполняться по-порядку, и оптимизатор не имеет права их переставлять.
При этом они ещё точки следования вставляют, так что ++ в безопасности.
Цитата Jin X @
Видимо, ^^ не стали делать как раз от греха подальше
Это обычное !=. Зачем?

Автор: Jin X 10.04.18, 12:34
Цитата OpenGL @
Не от греха подальше, а потому что операция бесмысленна. Главное отличие || от | (&& и &, соответственно), помимо того, что одна - логическая, а вторая - побитовая в том, что первая ещё и ленивая. А вот ^^ ленивой не сделать.
Если под ленивой ты подразумеваешь проверку одного условия из 2-х (если оно true для ||), то отчего ж && не ленивая (при первом false)?

Цитата Qraizer @
Это обычное !=. Зачем?
Точно. Тормознул чё-т я :facepalm: :) (see below)

Цитата Serafim @
но не до такой степени
Ну ладно... if (smthngBad1 || ++i && smthngBad2 || ++i && smthngBad3)
Как будто бы и не присвоение почти :D
(на всякий случай скажу, что согласен, что это говнокодинг, но выглядит прикольно, поэтому иногда так и подмывает так писать)

Добавлено
Цитата Qraizer @
Это обычное !=. Зачем?
Цитата Jin X @
Точно. Тормознул чё-т я
Хотя нет, не тормознул...
5 != 7 = true
но
5 ^^ 7 = false

Добавлено
Если только так извращаться:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    var x=5, y=7;
    alert((x&&1) != (y&&1));  // false
но это бред.

Автор: OpenGL 10.04.18, 13:01
Цитата Jin X @
Если под ленивой ты подразумеваешь проверку одного условия из 2-х (если оно true для ||), то отчего ж && не ленивая (при первом false)?

&& тоже ленивая уж. Имеется ввиду, что || в моём предложении ты можешь заменить на &&, а | на &.

Автор: Jin X 10.04.18, 13:02
Вот, блин!
В JS:
5&&1 = 1, а 1&&5 = 5
5||0 = 5 и 0||5 = 5 (почему одинаково - понятно, но почему не true/false?)
Чё за бред? :wall:

p.s. В сях всё нормально работает: везде выдаёт 1 или true (в т.ч. для 2&&1 и 1&&~1, что ожидаемо).

Добавлено
Цитата OpenGL @
Имеется ввиду, что || в моём предложении ты можешь заменить на &&, а | на &.
Что??? :blink:

Добавлено
OpenGL, ты имеешь в виду, что && и || ленивые в отличие от & и | ?
А разве основная ценность в этой ленивости? И это достаточная причина, чтобы не делать ^^ ?
Ну реально бывает (редко, но бывает), что нужно сделать (x ^^ y). Можно, конечно, написать (!x != !y), но это тоже не вот прям офигеть как читаемо :)

Автор: Qraizer 10.04.18, 13:18
Цитата Jin X @
Хотя нет, не тормознул...
Ну это не серьёзно. Типы данных разные, и && и &, равно как и || и |, определены для разных типов, для которых есть взаимные касты, тогда как != одна на все типы, и кастов не требуется. Ты же не думаешь, что за типами следить не надо? А то я как-то видал в коде if(a != true), было весело писать багрепорты.

Автор: Jin X 10.04.18, 13:21
Цитата Qraizer @
Ты же не думаешь, что за типами следить не надо?
Надо, но всегда ли есть смысл писать if (x != 0), когда можно написать просто if (x) ?
А в случае с xor как-то тоже бредово выглядит if ((x && !y) || (!x && y)) и аналогично if ((x!=0 && y==0) || (x==0 && y!=0)).
Как ты предлагаешь реализовать xor, чтобы получилось красиво?

Добавлено
Цитата Jin X @
тоже бредово выглядит
Или:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    bool boolX = x, boolY = y;
    if (boolX != boolY) {...}
тоже не айс...

if ((bool)x != (bool)y) :no:

Добавлено
В JS соответственно:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    var boolX=!!x, boolY=!!y;
    if (boolX != boolY) {...}

Автор: OpenGL 10.04.18, 13:37
Цитата Jin X @
OpenGL, ты имеешь в виду, что && и || ленивые в отличие от & и | ?

Да.

Добавлено
Цитата Jin X @
А разве основная ценность в этой ленивости? И это достаточная причина, чтобы не делать ^^ ?

Имхо, да. Из-за ленивости ты сможешь написать что-то наподобие if(index < a.len() && a[index] < 42), и замена && на & тут не прокатит. ^^ же ровно с тем же успехом в большинстве случаев заменяется на ^.

Цитата Jin X @
Ну реально бывает (редко, но бывает), что нужно сделать (x ^^ y).

Когда x и y не булевские, и просто конвертятся неявным кастом? Я в этом случае просто сам сравниваю с нулём. Т.е. как-то if ((x != 0) ^ (y != 0)) пишу.

Автор: Jin X 10.04.18, 13:47
Периодически встречаются конструкции вида if x % 1 == 0 или if not 1 % 1 — проверка на целое (python)
Или n = ~~(n/5) — деление нацело (JS)
Прикольно, конечно, но в "чистоте" такого кода у меня сомнения...

Автор: OpenGL 10.04.18, 13:48
Цитата Jin X @
Надо, но всегда ли есть смысл писать if (x != 0), когда можно написать просто if (x) ?

Почему нет? В языках без неявного приведения к bool писать != 0 не напрягает совершенно.

Автор: Serafim 10.04.18, 13:48
Цитата Jin X @
Вот, блин!
В JS:
5&&1 = 1, а 1&&5 = 5
5||0 = 5 и 0||5 = 5 (почему одинаково - понятно, но почему не true/false?)
Чё за бред?

Я же написал даже, что есть языки, где операнды возвращают значение, а не булев результат: Чистота кода VS оптимизация (сообщение #3766081) пункт номер 1 ;)

Автор: Jin X 10.04.18, 13:50
Цитата OpenGL @
Т.е. как-то if ((x != 0) ^ (y != 0)) пишу.
Вариант, конечно (тогда можно использовать != – так понятнее).
Но это точно лучше, чем if (x ^^ y) (если бы он был)?

Добавлено
Цитата Serafim @
Я же написал даже, что есть языки, где операнды возвращают значение, а не булев результат
Сенькс. В Java так же?

Автор: OpenGL 10.04.18, 13:54
Цитата Jin X @
Это точно лучше, чем if (x ^^ y) (если бы он был)?

Зависит от того, как ты относишься к неявным кастам чисел к bool :-? Я вот за пределами олимпиад стараюсь их избегать, и поэтому даже if (a && b) у меня выглядит как if (a != 0 && b != 0)

Автор: Jin X 10.04.18, 13:56
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    #define XOR(a, b) (bool(a) != bool(b))
    . . .
    if (XOR(x, y)) {...}
:P

Автор: Serafim 10.04.18, 14:02
Цитата Jin X @
Сенькс. В Java так же?

Я не помню, кажется там каст к булеву. Тут тебе Астарот поможет.

А в Ruby и JS - 146% возврат значения. Плюс, в рубях и котлине сами операторы могут возвращать значение, типа:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    return if (errValue || errValue2) {
      throw Exception("Whoops!")
    } else {
      print("OK")
      do();
      true
    }

Автор: Jin X 10.04.18, 14:10
Цитата Serafim @
Плюс, в рубях и котлине сами операторы могут возвращать значение
C++
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    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;
    }


Добавлено
Или так :)
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    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;
    }

Автор: negram 10.04.18, 14:20
ммм. А как тема "Чистота кода VS оптимизация" превратилась в соревнование кто по-уродливее код написать может? :unsure:

Автор: Serafim 10.04.18, 14:28
Это значит, что любой оператор (хотя в котлине вроде только if):
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    verifyItems = (...args) => (i or throw Error "asd" for i of args).length


Применение для каждого элемента args функции, которая в случае элемента, который равен false вернёт ошибку, в остальных случаях значение аккумулируется и от него берётся length, т.е. количество элементов в результате (этот ваш незамысловатый i++ в if условии).

А вот даже можно собрать это всё

Автор: Qraizer 10.04.18, 14:30
Цитата Jin X @
Как ты предлагаешь реализовать xor, чтобы получилось красиво?
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    if(!!x != !!y) /* ... */
:D

Автор: Jin X 10.04.18, 14:36
Qraizer, ага. С одним ! не так красиво? :)

Автор: Qraizer 10.04.18, 15:17
Конечно, нет. Алгоритм-то другой.

Автор: Славян 10.04.18, 15:18
А я, Serafim, вообще стараюсь избегать фигурных, если позволительно, a'la:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    if( ... )
      A = B,
      func1( ... ),
      p = func2(...);
    else
      C = D, ...;
:blush:

Автор: Jin X 10.04.18, 15:27
Славян, ну это уже борщ, ИМХО :whistle:

Автор: Serafim 10.04.18, 17:28
Цитата Славян @
А я, Serafim, вообще стараюсь избегать фигурных, если позволительно, a'la:

А я джунов своих по рукам за это бью)

Автор: applegame 10.04.18, 17:39
Бедные джуны.

Автор: D_KEY 10.04.18, 17:44
Цитата Serafim @
Цитата Славян @
А я, Serafim, вообще стараюсь избегать фигурных, если позволительно, a'la:

А я джунов своих по рукам за это бью)

А тот код, что ты выше приводил, заставляешь писать? :lol:

Автор: Serafim 10.04.18, 17:44
Зато QA меньше проблем с "внезапно появившимися багами из ниоткуда" ;)

Добавлено
Цитата D_KEY @
А тот код, что ты выше приводил, заставляешь писать?

Допустим повышенный Complexity, как в примере выше, обычный анализатор сам подсветит, сложнее с Protected Variations и Cohesion - тут надо самому думать как не свалиться в рефакторинг)

Автор: Vesper 10.04.18, 18:14
Цитата Jin X @
А && имеет более высокий приоритет, чем ||.

Приоритет приоритетом, но флаг complete boolean eval означает вычислить все части булева выражения, даже если они уже не влияют на итоговый результат. Пример был вида "if (a<100) or add1(a) then..." где add1 - функция с сайд-эффектом, возвращающая boolean, и при B+ переменная а всегда увеличивалась, а при В- только если (а<100) было ложным. Вот мало ли кто захочет зачем-то поменять эту нас ройку, тем боле если в заголовке где-то проскочит, а особенно если это что-то фиг-отладишь типа буста. Вот надо им было, а ты теперь страдай.
Цитата OpenGL @
Хм, прочитал про это. Какому идиоту вздумалось вводить этот ключ? Это же трындец какой-то.

Сюрприз, да :D

Автор: Jin X 10.04.18, 18:50
Цитата 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 такого не надо делать :)

Автор: D_KEY 10.04.18, 19:48
Неужели кто-то ещё пишет на Delphi?

Автор: Jin X 10.04.18, 20:06
D_KEY, нет, конечно, никто не пишет.
Embarcadero чисто по загону новые версии выпускает. Для прикола, тупо поржать ;)

Автор: Qraizer 10.04.18, 21:56
Цитата Jin X @
...(которые там нафиг не нужны)
...чем напрочь запрещаем ASLR.

Автор: OpenGL 11.04.18, 05:56
Цитата Vesper @
Вот мало ли кто захочет зачем-то поменять эту нас ройку, тем боле если в заголовке где-то проскочит, а особенно если это что-то фиг-отладишь типа буста.

В плюсовых компиляторах тоже такая настройка имеется? Что-то сильно сомневаюсь. Максимум, что ты сделаешь в плюсах - перегрузишь логические операторы для своих типов. И вообще, можно пруф того, что это бывает не только в дельфи?

Автор: Jin X 11.04.18, 11:43
Цитата Qraizer @
чем напрочь запрещаем ASLR.
Чтобы ASLR работал, нужно либо включить соответствующие опции в PE-заголовке (при компиляции, например). Либо прописать эти опции в реестре для конкретного файла.
Но в целом ты прав, конечно.

Добавлено
Не углублялся в эту тему раньше.
Ну тогда вместо отключения фиксапов можно включать ASLR и DEP (ну или просто DEP хотя бы):
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    {$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.

Автор: Qraizer 11.04.18, 12:08
Без reloc-ов по-любому ASLR не заработает. Но тут как бы палка о двух концах. Во время отладки стрипать их даже полезно, ибо бряки, не привязанные к строкам кода, а поставленные, скажем, на конкретные ассемблерные инструкции, что нередко бывает нужно для либ без сыров, при активном ASLR слетают токатак. Но вот в релизе я удалять их всё-таки бы не советовал.

Автор: Jin X 11.04.18, 16:11
Цитата Qraizer @
Без reloc-ов по-любому ASLR не заработает.
Да это понятное дело.

Цитата Qraizer @
Во время отладки стрипать их даже полезно
Можно так:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    {$IFDEF DEBUG}
      {$SetPEFlags IMAGE_FILE_RELOCS_STRIPPED}
    {$ELSE}
      {$SetPEOptFlags IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE}
    {$ENDIF}
    {$SetPEOptFlags IMAGE_DLLCHARACTERISTICS_NX_COMPAT}
:)

Автор: Jin X 11.04.18, 17:59
Кстати, кто подскажет, что это за прога (которая показывает заголовок PE в таком виде)?

user posted image

user posted image

Автор: korvin 12.04.18, 20:17
Цитата Serafim @
Крупные методы принято делить на более мелкие, в частности твой вариант, в языках с возвращаемым значением в операндах (JS, Python, Ruby), вместо кастуемых (Java, PHP) моет выглядеть следующим образом:



А в нормальных следующим:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    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 чисто по загону новые версии выпускает. Для прикола, тупо порубить хоть чуть-чуть бабла на легаси-проектах

Ага.

Автор: Serafim 12.04.18, 22:53
Цитата 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, так что поправь, если ошибаюсь)

Автор: korvin 13.04.18, 08:35
Цитата Serafim @
Результат: функция "||" от a и b

Что?

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    {-
     
    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

Автор: amk 13.04.18, 15:39
Цитата Serafim @
1) C, Java, PHP: "res = a || b"
Результат: res = bool
Что значит bool? true если a, иначе true если b, иначе false. При проверке условия вместо возврата результата сразу производится переход к нужной ветке.
На самом деле вычисление результата тоже производится переходами.
То есть фактически в C res = a || b означает res = (a || b)? true: false

Цитата Serafim @
2) JS, Ruby, Python: "res = a || b"
Результат: res = a (если он тру) или b
В Python надо писать res = a or b. В остальном почти верно. При вычислении результата, сразу после определения значения выражения производится переход на точку сохранения результата.

Автор: Serafim 13.04.18, 21:26
Цитата amk @
Что значит bool?

Это означает, что там может находиться либо true, либо false и никак иначе.

Автор: amk 14.04.18, 08:19
Цитата Serafim @
Это означает, что там может находиться либо true, либо false и никак иначе.
Но не указано, что если по `a` можно определить ответ, то `b` не анализируется

Автор: Jin X 14.04.18, 14:40
amk, я думаю, это не сложно определить эмпирически :)

Автор: Serafim 14.04.18, 15:20
Цитата amk @
Но не указано, что если по `a` можно определить ответ, то `b` не анализируется

Да ладно? :o Ты уверен? :huh:

Автор: amk 14.04.18, 17:22
Уверен. В C это описано стандартом.
Так же и в C++, если переменные не являются пользовательскими типами.
Но в таком случае не может быть уверенности даже в результирующем значении. Пользовательский operator||() вовсе не обязан возвращать bool

Автор: OpenGL 14.04.18, 18:28
Цитата Serafim @
Да ладно? Ты уверен?

Так практически везде же.

Автор: Serafim 15.04.18, 09:22
Простите, я табличку сарказма потерял :D

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)