Почему опытные разработчики пишут тупой код и как распознать новичка за километр

Предлагаю читателям «Хабрахабра» перевод публикации «Why Senior Devs Write Dumb Code and How to Spot a Junior From A Mile Away» за авторством Scott Shipp.


Одна из моих любимых цитат на все времена — Брайана Гетца (Brian Goetz), умнейшего чувака из мира Java, одного из авторов «Java Concurrency in Practice», кроме всего прочего. Цитата взята из интервью, опубликованного на сайте Oracle под заголовком «Пишите тупой код» («Write Dumb Code»). Гетца спросили, как писать хорошо работающий код.

Вот что он ответил:

«Часто писать быстрый код на Java означает писать тупой код — код простой, чистый и следующий самым очевидным объектно-ориентированным принципам».

В остальных 1000 слов объяснялось, почему попытки оптимизировать код и попытки быть умными — это распространённые программерские ошибки, ошибки новичков, если хотите.

Код опытных разработчиков


Если вы, подобно мне, были когда-то джуниором, возможно, помните, как впервые исследовали код сениора и думали: «Я могу так писать. Почему я не сениор?».

Я длительное время пытался писать такой код, и у меня не получалось.

Загадочным в коде сениора было не то, что я не мог его понять, а что я мог его понять моментально. Он был конкретно тупым и казалось, что там должно быть что-то ещё. Я думал: «Где остальное? Как этот код делает всё это?»

С тех пор я изучил названия всех принципов и признаков кода, делающих его тупым: YAGNI, принцип единственной ответственности, DRY, принцип единственного уровня абстракции, слабое зацепление и т. д. И я стал сениором. На самом деле я ненавижу термин «сениор» и называю себя просто разработчиком ПО, но это другая история.

Главный урок, который я извлёк: писать тупой код трудно, но это приносит экспоненциальную выгоду.

Как отличить джуниора за километр


В книге «Refactoring: Improving the Design of Existing Code» Кент Бек говорит:

«Любой дурак может писать код, понятный компьютеру. Хорошие программисты пишут код, понятный людям.»

Вы всегда сможете узнать начинающего разработчика, просматривая код полный «умных» однострочников, сомнительных абстракций и массы специфических языковых конструкций. Я бы сказал, что последнее наиболее характерно. Это выглядит, как будто код пытается сказать: «Посмотри на меня! Мой создатель отлично знает язык! Я использую локальный потоковый синхронный конструктор копирования JavaBean с интерфейсом по умолчанию и непроверяемыми исключениями кастомных дженериков вместе с многофункциональным генератором кода JAXB Lombok с усиленной безопасностью!».

Да, я сказал чепуху, потому что в чепуху превращается код в руках тех, кто думает исключительно о компьютерной стороне вещей вместо человеческой.

Код — это общение между людьми и инструкции для компьютера, но значительно больше первое, чем второе. Компилятор сам заботится о преобразовании написанного программистом в машинный код. Часто имеет место несколько слоёв такого преобразования, например, когда Java компилируется в байт-код, который считывается виртуальной машиной и транслируется в итоге в нули и единицы.

Но код — это человеческий язык. Он объясняет все «кто», «что», «когда», «где», «как» и «почему» задачи, заодно давая инструкции компьютеру. Он должен иметь смысл и пять лет спустя, когда компания будет продана, и новая команда, никогда не видевшая этого кода, откроет его для улучшения и исправления.

Да, написание тупого кода — это трудно. Я убеждаюсь в этом всё больше и больше с течением времени. Я чувствую удовлетворение, когда получаю коменты типа: «Чистый код!» на код-ревью. Я знаю, что лучшая вещь, которую я могу сделать для своей команды и для будущих мейнтейнеров кода — писать тупой код.

Вот мысль, которую приписывают Dave Carhart:

«Всегда кодируй так, будто парень, который будет поддерживать твой код — необузданный психопат, и он знает, где ты живёшь».
Поделиться публикацией
Комментарии 407
    –16
    Достаточно тупой код чтоб быть синьёром?

    bool IsBukva(char symbol)
    {
    switch(symbol)
    {
    case'a':return 1;break;
    case'b':return 1;break;
    case'c':return 1;break;
    case'd':return 1;break;
    case'e':return 1;break;
    case'f':return 1;break;
    case'g':return 1;break;
    case'h':return 1;break;
    case'i':return 1;break;
    case'j':return 1;break;
    case'k':return 1;break;
    case'l':return 1;break;
    case'm':return 1;break;
    case'n':return 1;break;
    case'o':return 1;break;
    case'p':return 1;break;
    case'q':return 1;break;
    case'r':return 1;break;
    case's':return 1;break;
    case't':return 1;break;
    case'u':return 1;break;
    case'v':return 1;break;
    case'w':return 1;break;
    case'x':return 1;break;
    case'y':return 1;break;
    case'z':return 1;break;
    case'A':return 1;break;
    case'B':return 1;break;
    case'C':return 1;break;
    case'D':return 1;break;
    case'E':return 1;break;
    case'F':return 1;break;
    case'G':return 1;break;
    case'H':return 1;break;
    case'I':return 1;break;
    case'J':return 1;break;
    case'K':return 1;break;
    case'L':return 1;break;
    case'M':return 1;break;
    case'N':return 1;break;
    case'O':return 1;break;
    case'P':return 1;break;
    case'Q':return 1;break;
    case'R':return 1;break;
    case'S':return 1;break;
    case'T':return 1;break;
    case'U':return 1;break;
    case'V':return 1;break;
    case'W':return 1;break;
    case'X':return 1;break;
    case'Y':return 1;break;
    case'Z':return 1;break;
    default:return 0;
    }
    }
    
      +16
      Нет, недостаточно. Можно ещё тупее:

      if ((symbol >= 'a' && symbol <= 'z') || (symbol >= 'A' && symbol <= 'Z'))

      Речь не о том, что лучше или хуже, но так же реально тупее, если применять это слово к коду, а не к его автору :)
        +2
        Почему этот кусок кода тупой?
          +1

          Решает задачу наиболее простым образом

            0
            В принципе можно ещё подумать и найти ещё более тупой способ.
              0
              if (is_alpha(symbol))
                0
                а если symbol=='Ж'? В первом случае такого вопроса просто не возникает, здесь же придется смотреть контекст
                  +3
                  А если кодировка отличная от 7-битной? И язык, например, казахский? Не нужно строить лисапедов без необходимости.
            0
            Стандарт с++ не гарантирует порядок символов английского алфавита в char. Поэтому, чтобы проверить является ли символ буквой нужно пользоваться стандартной функцией std::isalpha.
            bool isBukva (char symbol)
            {
                return std::isalpha(symbol);
            }
            
              0
              Потому как легко пропустить одну букву, и функция будет вести себя не так, как ей положено.
              +8

              Вот только для русской кодировки такой однострочник не работал и пропускал букву Ё.

                0
                Или так if (std::tolower(symbol) != std::toupper(symbol))
                +8
                и не лень было набирать
                  +5

                  <C-r>=map(range(char2nr('a'), char2nr('z')) + range(char2nr('A'), char2nr('Z')), 'printf("case''%s'':return 1;break;", nr2char(v:val))')<CR>

                    +30

                    и не лень было набирать

                    0
                    Возможно это вывод в цикле в текстовый файл, программа из трех строчек… а уже написали ))
                      –14
                      Лень — плохое качество для программиста, говорю тебе как синьёр.
                        +10
                        Пфф. Лень — двигатель прогресса. Программисту лень что-то делать, и он это дело оптимизирует.
                          –9
                          Не спорь с синьёром!
                            +22
                            Лень — двигатель прогресса
                            Прогресс выводится на орбиту с помощью РН серии Союз-У, двигателями которого являются РД-117, РД-118 и РД-0110.
                            0
                            habrahabr.ru/post/275841
                            Цитата №8.
                          +19
                          Ну какой синьёр, вы букву пропустили
                            –5
                            Теперь я думаю почему индусы не сениоры
                              +8
                              Возможно, когда-то давно, во времена EBCDIC и других альтернативных (не ASCII) кодировок, это и был тот самый «тупой», зато платформо-независимый код.
                                0
                                Как показывает моя практика, времена EBCDIC еще не прошли =)
                                +6
                                Не тянешь на синьора. Тупизна кода достаточная, но функция должна возвращать bool, а ты возвращаешь int.
                                • НЛО прилетело и опубликовало эту надпись здесь
                                    +1
                                    Тем не менее, в этом случае объявление функции подразумевает, что где-то выше по коду было
                                    #define bool int
                                    что в свою очередь, как правило, сопровождается
                                    #define false 0
                                    #define true 1

                                    Поэтому было бы «элегантно» и возвращать true или false.
                                      0
                                      Пришла в голову мысль, что bool может быть объявлен через typedef, а использовать #define запрещено coding style, используемым в компании. Но и тогда, наверное, можно было бы true и false через enum определить.
                                        +1

                                        Вообще‐то bool (как и true и false) по стандарту C99 именно макросы, раскрываемые как _Bool (1 и 0). Стандарт даже разрешает программе переопределять их (правда, сразу объявляет такую возможность устаревшей). Но #define bool int — это что‐то сомнительное, sizeof(_Bool) обычно единица, что означает, что вы не сможете с таким определением принимать bool * из библиотек на C99. А при другом соглашении о вызовах или порядке байт и просто bool передавать и принимать также не сможете.

                                    +1
                                    Вообще-то bool, посмотри внимательней
                                      –1
                                      Это как раз то, о чём говорится в статье. Да, 0 и 1 будет преобразованы в правильный bool — но это как раз шажок на пути к я использую локальный потоковый синхронный конструктор копирования JavaBean с интерфейсом по-умолчанию и непроверяемыми исключениями кастомных дженериков вместе с многофункциональным генератором кода JAXB Lombok с усиленной безопасностью
                                    0

                                    Под такой тип кода есть даже специальный термин: "китайский код" :)

                                      0
                                      Дело не в тупости, а в читаемости. И ваш код для чтения неудобен, по той простой причине, что не умещается на экран.
                                        +7
                                        И ваш код для чтения неудобен, по той простой причине, что не умещается на экран.

                                        Не проблема
                                        bool IsBukva(char symbol){switch(symbol){case'a':return 1;break;case'b':return 1;break;case'c':return 1;break;case'd':return 1;break;case'e':return 1;break;case'f':return 1;break;case'g':return 1;break;case'h':return 1;break;case'i':return 1;break;case'j':return 1;break;case'k':return 1;break;case'l':return 1;break;case'm':return 1;break;case'n':return 1;break;case'o':return 1;break;case'p':return 1;break;case'q':return 1;break;case'r':return 1;break;case's':return 1;break;case't':return 1;break;case'u':return 1;break;case'v':return 1;break;case'w':return 1;break;case'x':return 1;break;case'y':return 1;break;case'z':return 1;break;case'A':return 1;break;case'B':return 1;break;case'C':return 1;break;case'D':return 1;break;case'E':return 1;break;case'F':return 1;break;case'G':return 1;break;case'H':return 1;break;case'I':return 1;break;case'J':return 1;break;case'K':return 1;break;case'L':return 1;break;case'M':return 1;break;case'N':return 1;break;case'O':return 1;break;case'P':return 1;break;case'Q':return 1;break;case'R':return 1;break;case'S':return 1;break;case'T':return 1;break;case'U':return 1;break;case'V':return 1;break;case'W':return 1;break;case'X':return 1;break;case'Y':return 1;break;case'Z':return 1;break;default:return 0;}}
                                          +2
                                          Так он в экран уместился, но удобнее для чтения не стал.
                                            0
                                            Разбор аргументов в gradlew

                                            case $i in
                                              (0) set -- ;;
                                              (1) set -- "$args0" ;;
                                              (2) set -- "$args0" "$args1" ;;
                                              (3) set -- "$args0" "$args1" "$args2" ;;
                                              (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
                                              (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
                                              (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
                                              (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
                                              (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
                                              (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
                                            esac
                                            
                                              –1
                                              Ну это ж shell! Какую вы предлагаете альтернативу без bash'измов?
                                                0

                                                Видите там наверху цикл? Он категорически некорректен (не делает экранирование правильно), но там вполне можно было написать setcmd="set --" ; for arg ; do setcmd="$setcmd \"\$args$i\"", а потом использовать eval. Это если конечно данный set вообще нужен, может быть его лучше заменить на что‐то другое — я так далеко не копал.

                                                  0
                                                  Это если конечно данный set вообще нужен, может быть его лучше заменить на что‐то другое — я так далеко не копал.
                                                  Они в конце exec делают, тут без set в POSIX shell'е не обойтись.

                                                  Он категорически некорректен (не делает экранирование правильно), но там вполне можно было написать setcmd="set --" ; for arg ; do setcmd="$setcmd \"\$args$i\"", а потом использовать eval.
                                                  Ну вот как раз то место сделано довольно-таки дико. `echo args$i` — это просто пять баллов.

                                                  Да, пожалуй. Если они уже всё равно «замарались» в eval, то вариантов особо-то и нет: лучше один раз правильно сформировать команду, чем делать то, что они творят…
                                                    0

                                                    В POSIX shell без eval не очень много можно сделать. Я вот как‐то писал парсер --ключей: https://github.com/neovim/neovim/blob/c693afb8ac0aea94bc268f880511d7b7f3710d2c/scripts/pvscheck.sh#L76-L243 (вообще по‐хорошему надо бы в библиотеку оформить), там eval используется аж 19 раз (а вот echo — ровно один, и то в месте, где его вызов соответствует принципу «garbage in — garbage out»).

                                          0
                                          Вы не поверите, но встречал подобный код в продакшене. Там перебором соотносились номера в очень большой гостинице и их порядок. Причем делалось это в нескольких местах.
                                            +1
                                            Почему мне нравится Питон:

                                            import string
                                            symbol = 'a'
                                            if symbol in string.ascii_letters:
                                            print(«I'm a letter!»)
                                              0
                                              Перебирать каждый раз массив? Твоё решение ещё хуже приведённого выше.
                                                +1
                                                Видимо, опыт сказывается)
                                            +1
                                            Вот мысль, которую приписывают Dave Carhart:

                                            Насколько я знаю, это был John F. Wood.
                                              +1
                                              Да, видел такую версию, когда делал перевод. Тут я склонен предположить, что уже в те времена это был известный в узких кругах мем, а Джон просто его процитировал.
                                              В оригинале же упоминался именно Дейв, и ему тоже эту цитату приписывают, так что решил оставить его.
                                                0
                                                ага, тоже в глаза бросилось
                                                +2
                                                Я часто применяю тернарные операторы, вместо if else, это тупой код? А еще последнее время стараюсь все связанное со списками делать через LINQ, в т.ч. foreach. Это ухудшает читаемость? По-моему нет, но это и понятно, иначе я бы так не писал.
                                                  +7
                                                  А еще последнее время стараюсь все связанное со списками делать через LINQ, в т.ч. foreach. Это ухудшает читаемость?

                                                  Читаемость улучшает, отлаживать сложнее (промежуточные значения не видно).

                                                    0
                                                    Есть хороший дебаггер для LINQ www.oz-code.com
                                                    Но он платный. Надеюсь в будущих студиях или в решарпер добавят такую функциональность.
                                                    0
                                                    Я часто применяю тернарные операторы, вместо if else, это тупой код?

                                                    Нет, это машиночитаемый код. Человеку проще if-else прочитать как бы… Да и в дебаге сильно удобнее, да.

                                                      +7
                                                      Всегда ли проще читать?
                                                      var a = cond ? GetVal1() : getVal2();

                                                      SomeType a = null;
                                                      if(cond)
                                                      {
                                                          a = GetVal1();
                                                      }
                                                      else
                                                      {
                                                          a = getVal2();
                                                      }
                                                      


                                                      Ну и студия позволяет ставить брейкпойнты в ветках тренарного оператора записанного в одну строку.
                                                        0
                                                        // Variant 1
                                                        var a = cond 
                                                            ? GetVal1()
                                                            : GetVal2();
                                                        
                                                        // Variant 2
                                                        SomeType a = null;
                                                        if(cond) { a = GetVal1(); }
                                                        else { a = getVal2(); }
                                                        
                                                        // Variant 3
                                                        SomeType a = null;
                                                        if(cond) 
                                                            { a = GetVal1(); }
                                                        else 
                                                            { a = getVal2(); }

                                                        На вкус и цвет…
                                                          +3
                                                          первый всё ещё более читаемый.
                                                            0
                                                            На PHP можно даже без скобок
                                                            // Variant 4
                                                            $a = null;
                                                            if($cond)  $a = getVal1(); 
                                                            else $a = getVal2();

                                                            Но это не значит, что нужно так писать. Обычно такое должно регулироваться стайл гайдами.
                                                            –1
                                                            Теперь я начинаю понимать авторов, которые пишут:
                                                            if (cond) 
                                                            {
                                                              return true;
                                                            }
                                                            else
                                                            {
                                                              resturn false;
                                                            }

                                                            Раньше меня такие конструкции приводили в недоумение…
                                                              +1
                                                              Им платят за строчки кода. Если бы они просто назвали `cond` читаемым именем не надо было бы городить костыли.
                                                                0
                                                                не понимаю вашу мысль. Как это связано с моим комментарием?
                                                                  +2
                                                                  Теперь я начинаю понимать авторов, которые пишут:
                                                                  if (cond) 
                                                                  {
                                                                  return true;
                                                                  }
                                                                  else
                                                                  {
                                                                  resturn false;
                                                                  }

                                                                  Так пишут не для простого кода и читаемости.
                                                                  А пишут от непонимания даже базовых типов и операторов.


                                                                  Еще часто встречается такой код:


                                                                  return cond ? false : true;

                                                                  var result = cond ? false : true;

                                                                  Или такой:


                                                                  var result = someValue == 0 ? true : false;

                                                                  И высший пилотаж (скобки на всякий случай для уверенности):


                                                                  var result = (someValue == 0 ? true : false);

                                                                  Что характерно, эти портянки как раз и объяснялись необходимостью "простого кода, понятного любому разработчику, не знающего тонкости языка".


                                                                  Вместо того, чтобы написать:


                                                                  return cond;

                                                                  return someValue == 0;
                                                                    +1
                                                                    var result = (someValue == 0 ? true : false);

                                                                    Я тоже ставлю скобки в таких выражениях. Без скобок при быстром чтении внутренний парсер сбивается. И визуально оно разделяется на 2 части по знаку ==, а не по =.
                                                                    someValue = a + b;
                                                                    result = someValue == 0 ? result1 : result2;
                                                                    // someValue равно a плюс b
                                                                    // result равно someValue, ой то есть bool, ой тут тернарный оператор, еще раз, result равно (someValue равняется нулю | да ... нет ...)
                                                                    
                                                                      0
                                                                      А почему бы тогда так не писать для пущей надежности?:
                                                                      var result = ((someValue == 0) ? true : false);


                                                                      Впрочем, если мы возвратимся к сути примера, то все гораздо проще:
                                                                      var result = someValue == 0;

                                                                      Ну или ок, пусть так:
                                                                      var result = (someValue == 0);

                                                                      В любом случае, все ясно и кратко, и можно со скобками, можно без.

                                                                      А то ведь можно дойти и до такого (почему нет)?:
                                                                      var result = ((someValue == 0) ? (true ? true: false ) : (false ? false : true));

                                                                        0
                                                                        А почему бы тогда так не писать для пущей надежности?
                                                                        Тут необязательно, так как в тернарном операторе первое условие всегда логическое. Хотя если условие будет длинное, то лучше поставить.

                                                                        А то ведь можно дойти и до такого (почему нет)?
                                                                        Потому что не повышает читаемость.

                                                                        В любом случае, все ясно и кратко, и можно со скобками, можно без.
                                                                        Согласен. С другой стороны, это отвязка от конкретно булевского типа, так проще рефакторить. Например, мы в новом коде сделали true/false, но не уверены, возможно потом будет лучше сделать 0/1/-1. Так мы можем просто заменить значения в ветках на любой другой тип. Но это редко когда нужно.
                                                                          0
                                                                          А то ведь можно дойти и до такого (почему нет)?

                                                                          (true ? true : false) // -> true
                                                                          (false ? false : true) // -> true
                                                                          

                                                                          ???
                                                                        +1
                                                                        Ну, у меня например не return, так что…

                                                                        Для не обрывающегося случая я всегда ставлю скобки, даже если там 1 оператор. Потому это однозначно, и не зависит от отступов. Был нет так давно весёлый баг в популярном опенсорсе:
                                                                        if (cond)
                                                                          SomeFunc();
                                                                        + SomeOtherFuncThatMusBeInIFBlock();

                                                                        OtherMethods();

                                                                          –1

                                                                          return cond ? false : true; и return cond; в целом неравнозначны :) А если имелось в виду return cond ? true : false;, то в некоторых языках и они не равнозначны, если cond не строго булевого типа, а лишь в некоторых случаях типа if (func()) неявно приводится к нему. Даже если типа bool вообще нет, как в C (или уже есть?) и где-то в языке заложено #define true 1, то return cond; в случае когда cond может отказаться равно, например, 2, может приводить к сложно диагностируемым ошибкам, если клиент func() ожидает строго 1 или 0 в возврате.

                                                                            0

                                                                            Это опечатка, имелось в виду, конечно, return cond? true: false.
                                                                            Если результат нужно инвертировать, то тернарный оператор также не нужен, достаточно написать return !cond.


                                                                            Это я написал про C# и код на нем, который часто доводится видеть.


                                                                            Что касается других языков, того же C, то там нужно смотреть какие конкретно нужны значения, и их и возвращать.
                                                                            (Обычно там всегда 0 для false, а для true есть варианты, обычно используются разные подходы в зависимости от 8/16/32-разрядности, либо 1, либо "не ноль", либо минус 1.)
                                                                            И бездумность применения операторов, в отличие от C#, кроме некрасивого и избыточного кода, принесет и реальные ошибки.

                                                                              0

                                                                              Если можно получить bool унарным !, то не логичнее ли просто два раза инвертировать, если инвертировать не нужно, а bool нужен?

                                                                                0

                                                                                Верно, я про это и пишу. Когда видишь код:


                                                                                return cond? true: false;

                                                                                то хочется предложить еще варианты:


                                                                                return !!cond;
                                                                                  0

                                                                                  А вот такой вариант приведения к bool уже воспринимается менее однозначно чем cond ? true : false в общем случае, вплоть до допускания возможности, что транслятор просто проигнорирует двойное отрицание в целях оптимизации. Тут уже нужно в доки языка лезть.

                                                                                    +1

                                                                                    Так в том то и дело, что C#, о котором изначально шла речь, cond? true: false не выполняет приведения к bool.
                                                                                    cond — уже(!) bool.
                                                                                    Тернарный оператор в C# предназначен для возвращения одного из двух значений какого-либо другого типа, отличного от bool (а приведение он не умеет делать — попробуйте поиграться хотя бы с Nulllable/NotNullable/null).
                                                                                    Если он возвращает bool — это избыточный код, который как минимум замусоривает код, и хорошо еще, если компилятор это убирает.


                                                                                    И да, доки читать нужно. Т.к. в любом языке все операторы и ключевые слова выглядят примерно одинаково (да и возможный набор моделей более-менее одинаков — процедурная/ОО/ФП), а значить могут весьма разное — если смотреть как именно это работает, а не по верхам.

                                                                                      0
                                                                                      и хорошо еще, если компилятор это убирает.
                                                                                      убирает
                                                                                        0

                                                                                        Ну, если cond гарантированно является bool и, желательно, это видно на одном экране с тернарником, то, да, излишний код cond? true: false, но !!cond вообще сбивает с толку в таком случае, наталкивает на мысли об ошибке, что имелось в виду одинарное отрицание.


                                                                                        Про доки в целом согласен, но при ревью подобного не библиотечного кода лично я бы учитывал насколько в конкретной компании распространена, как иногда говорится, гетерогенность разработки. В частности, если заведомо известно, что много разработчиков, часто переключающихся между языками, то я бы старался не допускать код, связанный с нюансами конкретного языка.

                                                                                          0

                                                                                          В C#, Java (и, предполагаю, в любом современном статически типизированном языке, кроме C) в выражении cond? A: B первый операнд (cond) всегда является bool, иначе код не скомпилируется.


                                                                                          И это не относится к тем нюансам языка, которые могут запутать даже опытного разработчика.
                                                                                          Это самые базовые вещи.


                                                                                          Пытаться усложнять этот код, чтобы он был якобы более читаемым, это все равно что пытаться как-то усложнить запись вызова оператора умножения чисел ("а вдруг у нас гетерогенная разработка, и этот код прочитает программист Руби, а в Руби можно умножать строку на число — давайте напишем вызов оператора умножения, чтоб явно было видно, что мы перемножаем числа").

                                                                                            0
                                                                                            В C#, Java (и, предполагаю, в любом современном статически типизированном языке, кроме C)
                                                                                            Потому что в C# и Java более строгая типизация, чем в С. Это о современности особо не говорит.
                                                                                0

                                                                                bool в C уже давно есть, и приведение к нему, явное или неявное, может выдать только true или false. Хотя вы всё ещё можете получить сложнодиагностируемую ошибку, если будете заполнять bool * какими‐нибудь двойками через memset() или любым другим из кучи обходных путей — минимально адресуемая единица памяти до сих пор байт и один bool (если он не битовое поле в структуре) будет занимать именно его.

                                                                                  0
                                                                                  Хотя вы всё ещё можете получить сложнодиагностируемую ошибку, если будете заполнять bool * какими‐нибудь двойками через memset() или любым другим из кучи обходных путей — минимально адресуемая единица памяти до сих пор байт и один bool (если он не битовое поле в структуре) будет занимать именно его.

                                                                                  Даже в C# такое возможно — заполнять bool произвольным однобайтным значением, пометив код как unsafe, либо использовать структуры и FieldOffset из средств маршаллинга данных в/из неуправляемого кода.
                                                                                  В последнем случае не потребуется помечать код как unsafe и, соответственно, код не потребует привилегий при исполнения.
                                                                                  А поведение при работе с такой булевой переменной будет с ошибками, и еще будет зависеть от версии компилятора.

                                                                                  +1
                                                                                  Даже если типа bool вообще нет, как в C (или уже есть?) и где-то в языке заложено #define true 1, то return cond; в случае когда cond может отказаться равно, например, 2, может приводить к сложно диагностируемым ошибкам
                                                                                  Можно использовать код
                                                                                  return !!cond;
                                                                                  В boost это очень распространено.
                                                                                  0
                                                                                  if (cond) 
                                                                                  {
                                                                                      return true;
                                                                                  }
                                                                                  else
                                                                                  {
                                                                                      return false;
                                                                                  }
                                                                                  Так пишут не для простого кода и читаемости.
                                                                                  А пишут от непонимания даже базовых типов и операторов.
                                                                                  Не всегда. Я, например, так пишу для того, чтобы при дебаге можно было поставить breakpoint на конкретную строчку на конкретное условие. Обычно, правда, в репозиторий это не идет, если ушло — значит, не заметил, поправлю на review.
                                                                                    0
                                                                                    Естественно, должно быть без фанатизма в плане краткости кода.
                                                                                    Иногда есть смысл в коде с таким ветвлением (хотя в случае дебага можно воспользоваться точкой останова с условием).
                                                                                    Бывает еще, когда ветвление более не только более читаемо, но и более масштабируемо — в том смысле, что может ожидаться, что блоки будут расширены дополнительным кодом.
                                                                                      0
                                                                                      в случае дебага можно воспользоваться точкой останова с условием
                                                                                      В VC++, к сожалению, скорость дебага от этого падает в несколько раз.
                                                                                –1
                                                                                Строго говоря — этот код не идентичен. В случае тернарного оператора в любом случае будут вычислены оба выражения.
                                                                                0
                                                                                Ну и студия позволяет ставить брейкпойнты в ветках тренарного оператора записанного в одну строку
                                                                                От языка зависит. В плюсах — нет, не позволяет.
                                                                                  0
                                                                                  В начале треда говорится про Linq. В c# позволяет.
                                                                                  0

                                                                                  Пока в функции ровно одна строка — тернарник будет удобнее, как только он оказывается посреди тела функции хотя бы в 5 строчек размером — он резко теряется.
                                                                                  Изредка и только короткие тернарники действительно читаются легче, чем условия, но


                                                                                  PS всегда был приверженцем сокращённо-выделенного вида:


                                                                                  SomeType a;
                                                                                  if (condition) {
                                                                                    a = getVal1();
                                                                                  } else {
                                                                                    a = getVal2();
                                                                                  }

                                                                                  PPS


                                                                                  Ну и студия позволяет ставить брейкпойнты в ветках тренарного оператора записанного в одну строку.

                                                                                  на строку брекпоинт можно поставить легко быстро и удобно, с поблочными всё же наверное побольше телодвижений надо сделать?

                                                                                    +1
                                                                                    бы в 5 строчек размером — он резко теряется.
                                                                                    Значит форматирование функции хромает. Так или иначе, мой коммент был про то, что if не всегда читаемее, чем ?:. А испоганить читаемость тренарного оператора можно просто длинной любого из трех его выражений.

                                                                                    на строку брекпоинт можно поставить легко быстро и удобно, с поблочными всё же наверное побольше телодвижений надо сделать?

                                                                                    F9 (мышкой, наверное, нельзя не уверен)
                                                                                      0
                                                                                      Значит форматирование функции хромает. Так или иначе, мой коммент был про то, что if не всегда читаемее, чем ?:. А испоганить читаемость тренарного оператора можно просто длинной любого из трех его выражений.

                                                                                      Ну вот порефакторили имя переменной и стало грустно читать. А кому-то и изначально было грустно читать. В общем как я написал — тернарник хорош в случаях когда он получается коротенький-маленький. В остальных случаях его использовать опасно/вредно для читабильности кода.

                                                                                  0
                                                                                  все дело в привычке. Для простых условий, как по мне, намного проще прочитать однострочный тенарный оператор чем продиратся через четыре строчки if-else
                                                                                  для меня такой вариант намного понятнее
                                                                                  ClosesType closes = isColdOutside ? COAT : TSHIRT

                                                                                  чем
                                                                                  ClosesType closes;
                                                                                  if (isColdOutside)
                                                                                      closes = COAT
                                                                                  else
                                                                                      closes = TSHIRT 
                                                                                  
                                                                                0
                                                                                Там семантика (обычно) разная: LINQ — query, foreach — command.

                                                                                Осмысленный выбор читаемость улучшает.
                                                                                  +1
                                                                                  Работал много лет назад с одним парнем. Он писал вот так:
                                                                                  subCategoryName = subCategoryName == 'Pets and animals' ? 'Animals' : subCategoryName == 'Food and wine' ? 'Food/wine' : subCategoryName == 'Opinions and philosophy' ? 'Opinions' : subCategoryName == 'Health and wellness' ? 'Wellness' : subCategoryName == 'Design and architecture' ? 'Design' : subCategoryName;


                                                                                    +2
                                                                                    О! Так это же я был))) Не то чтобы часто, но использую конструкцию.

                                                                                    Кстати, если разбить по строкам читается на удивление хорошо. Прув:

                                                                                    subCategoryName = subCategoryName == 'Pets and animals' ? 'Animals' : 
                                                                                                      subCategoryName == 'Food and wine' ? 'Food/wine' : 
                                                                                                      subCategoryName == 'Opinions and philosophy' ? 'Opinions' : 
                                                                                                      subCategoryName == 'Health and wellness' ? 'Wellness' : 
                                                                                                      subCategoryName == 'Design and architecture' ? 'Design' : 
                                                                                                      subCategoryName;
                                                                                    


                                                                                    Вот за использование производной группировки в исходной же переменной стоило бы попинать.
                                                                                      –1
                                                                                      Не заметить в этой простыне = вместо == и искать потом баги — бесценный опыт. Так и становятся сеньорами =)
                                                                                        +1
                                                                                        Ага у нас один индиец таким вот кодом биллинг запортачил. Перепутал == и =. Месяц одним клиентам приходили лишние счета, а другие получали сервис бесплатно. Сеньором он становится будет в другом месте.
                                                                                          +3
                                                                                          Сеньором он становится будет в другом месте.

                                                                                          И ведь станет!
                                                                                            0
                                                                                            true story — много таких)
                                                                                        +1
                                                                                        Он именно в строку писал. Этот код у меня хранится специально для аргументов про тернарные операторы. :)
                                                                                        Да, так намного лучше.
                                                                                          +1
                                                                                          За написание тернарников в одну строку и без скобок надо сразу лишать печенек.

                                                                                          Тернарная запись, если не читается однозначно — это источник батхерта, особенно при отладке. Не говоря о отладке чужих багов;)
                                                                                          +3
                                                                                          А почему бы не завести какой-нибудь Map<String,String> для такого дела? (не знаю, на каком языке этот код написан; сравнение строк по значению накладывает ряд ограничений, но вариантов все-равно больше одного).
                                                                                            0
                                                                                            Ну обычно такая конструкция заводится неожиданно. Сперва одно условие, потом два и понеслась. Проще дописать одно условие, чем феншуизироваться с риском ошибки.

                                                                                            Кроме того условие может быть немного нестандартным, например с регэкспом.

                                                                                            Ессно, в какой-то момент такую вещь феншуизируешь… Или нет.

                                                                                            Но, тем не менее, такой код читается. И часто лучше, чем map ;)
                                                                                          –1
                                                                                          можно и так, если грамотно форматировать. Пример из книги «Анализ программного кода на примере проектов Open Source», стр 69
                                                                                          op = 
                                                                                          &(
                                                                                                   !y ? (!x ?  upleft :  x != last ?   upper :   upright ) :
                                                                                          y != bottom ? (!x ?    left :  x != last ?  normal :     right ) :
                                                                                                        (!x ? lowleft :  x != last ?   lower :  lowright )
                                                                                          ) [w->orientation]

                                                                                          В ёлочку код не всегда читабельнее
                                                                                            –2
                                                                                            Какая — то фигня
                                                                                              0
                                                                                              можно и так, если грамотно форматировать.

                                                                                              А потом из-за изменения длины одной переменной или константы меняем всё выражение.
                                                                                                0

                                                                                                И хорошо, если успели заметить, что код потёк.

                                                                                                  0
                                                                                                  Наглядность кода стоит усилий.
                                                                                                0
                                                                                                И где он теперь?
                                                                                                  0
                                                                                                  Ну, если после двоеточия переносить проверку следующего условия на новую строку под предыдущей проверкой, то тоже ничего читается.
                                                                                                    0
                                                                                                    Вот нашёл такой кусочек кода (строка длиной 2834 символа) в проекте:

                                                                                                    bool specChanged = cur.SpecificNodesParameters.Nodes != prev.SpecificNodesParameters.Nodes || (cur.SpecificNodesParameters.Nodes && (cur.SpecificNodesParameters.Objects != prev.SpecificNodesParameters.Objects || (cur.SpecificNodesParameters.Objects && (cur.SpecificNodesParameters.Attributes != prev.SpecificNodesParameters.Attributes || (cur.SpecificNodesParameters.Attributes && (cur.SpecificNodesParameters.AttributeData != prev.SpecificNodesParameters.AttributeData || cur.SpecificNodesParameters.AttributeInfo != prev.SpecificNodesParameters.AttributeInfo)) || cur.SpecificNodesParameters.Measurements != prev.SpecificNodesParameters.Measurements || (cur.SpecificNodesParameters.Measurements && (cur.SpecificNodesParameters.MeasurementData != prev.SpecificNodesParameters.MeasurementData || cur.SpecificNodesParameters.MeasurementInfo != prev.SpecificNodesParameters.MeasurementInfo)) || cur.SpecificNodesParameters.OperativeMeasurements != prev.SpecificNodesParameters.OperativeMeasurements || (cur.SpecificNodesParameters.OperativeMeasurements && (cur.SpecificNodesParameters.OperativeMeasurementData != prev.SpecificNodesParameters.OperativeMeasurementData || cur.SpecificNodesParameters.OperativeMeasurementInfo != prev.SpecificNodesParameters.OperativeMeasurementInfo)) || cur.SpecificNodesParameters.MonitoringValues != prev.SpecificNodesParameters.MonitoringValues || (cur.SpecificNodesParameters.MonitoringValues && (cur.SpecificNodesParameters.MonitoringValueData != prev.SpecificNodesParameters.MonitoringValueData)) || cur.SpecificNodesParameters.UserValues != prev.SpecificNodesParameters.UserValues || cur.SpecificNodesParameters.Events != prev.SpecificNodesParameters.Events || (cur.SpecificNodesParameters.Events && (cur.SpecificNodesParameters.EventData != prev.SpecificNodesParameters.EventData || cur.SpecificNodesParameters.EventInfo != prev.SpecificNodesParameters.EventInfo)) || cur.SpecificNodesParameters.ObjectInfo != prev.SpecificNodesParameters.ObjectInfo)) || cur.SpecificNodesParameters.Query != prev.SpecificNodesParameters.Query || (cur.SpecificNodesParameters.Query && (cur.SpecificNodesParameters.Response != prev.SpecificNodesParameters.Response || (cur.SpecificNodesParameters.Response && (cur.SpecificNodesParameters.NodeQueryResponseData != prev.SpecificNodesParameters.NodeQueryResponseData)) || cur.SpecificNodesParameters.NodeQueryStatusData != prev.SpecificNodesParameters.NodeQueryStatusData)) || cur.SpecificNodesParameters.NodeConfigData != prev.SpecificNodesParameters.NodeConfigData || cur.SpecificNodesParameters.NodeConnectionData != prev.SpecificNodesParameters.NodeConnectionData || cur.SpecificNodesParameters.NodeStatusData != prev.SpecificNodesParameters.NodeStatusData || cur.SpecificNodesParameters.NodeInfo != prev.SpecificNodesParameters.NodeInfo));


                                                                                                    P.S. Беспокоиться не стоит — это автосгенерённый код. Если выровнять — будет около полсотни вполне красивых строчек.
                                                                                                      0
                                                                                                      P.S. Беспокоиться не стоит — это автосгенерённый код.
                                                                                                      Я долго не мог понять почему мне новенький разработчик жаловался. Оказалось он читал .min.js
                                                                                                        +1
                                                                                                        Было бы хуже, если бы он в этом файле разобрался и прислал патч.
                                                                                                    +1
                                                                                                    Частенько замена foreach на LINQ действительно ухудшает читаемость, за этим надо внимательно следить…
                                                                                                      0
                                                                                                      Частенько и наоборот.
                                                                                                    +4

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


                                                                                                    P.S. Если кто не понял — я не за преждевременную оптимизацию и нечитаемые полотна

                                                                                                      0

                                                                                                      Это кстати не про все ЯП. В том же rust функциональщина как минимум так же быстра, как императивщина. Иногда чуточку быстрее. Впрочем rust изначально несёт в себе бо́льшую сложность.

                                                                                                        0

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

                                                                                                          +1

                                                                                                          Для начала как хранятся данные о связях? Какие части нам требуется оптимизировать? https://en.wikipedia.org/wiki/Graph_%28abstract_data_type%29 (вопросы чисто риторические)


                                                                                                          Добавь я эти поля в граф — было бы менее красиво

                                                                                                          Я не силён в java, но там нет выбора между хранением по ссылке/по значению?


                                                                                                          Всмысле

                                                                                                          чем отличается


                                                                                                          struct Foo {
                                                                                                            a: i32,
                                                                                                            b: bool,
                                                                                                            c: String,
                                                                                                          }
                                                                                                          
                                                                                                          struct Bar {
                                                                                                            n: isize,
                                                                                                            foo: Foo,
                                                                                                          }

                                                                                                          От


                                                                                                          struct Baz {
                                                                                                            n: isize,
                                                                                                            a: i32,
                                                                                                            b: bool,
                                                                                                            c: String,
                                                                                                          }

                                                                                                          В большинстве компилируемых ЯП разницы нет. Алсо есть же дженерики и в той же java.

                                                                                                            0

                                                                                                            Данные о связях хранятся по-сути в списках смежности.


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


                                                                                                            Например есть параметр "важности" узла, ух, не знаю правильный термин.


                                                                                                            Попытка объяснить

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


                                                                                                            И этот параметр рассчитывается. И состояние узла в данный момент — отказал/не отказал. Нет смысла мешать их с самой структурой графа, это нарушение принципа единственной ответственности на мой взгляд.


                                                                                                            P.S. Не java, а c#, но они очень похожи.

                                                                                                              –1
                                                                                                              Я не силён в java, но там нет выбора между хранением по ссылке/по значению?
                                                                                                              Нет. Несколько примитивных типов (фиксированный список) передаются по значению, остальные — по ссылке.

                                                                                                              Одна из вещей, который в C# поправили, когда это была просто «улучшенная Java от Microsoft» (в дальнейшем дорожки двух языков разошлись и современный C# и Java отличаются весьма сильно).
                                                                                                                0

                                                                                                                Всё передается по значению, но для ссылочных типов значение является ссылкой. Это не то же самое, что передача по ссылке. Например, нельзя написать функцию, которая меняет местами аргументы (в отличие от, скажем, C++, где есть передача по ссылке).

                                                                                                                  –1
                                                                                                                  в отличие от, скажем, C++, где есть передача по ссылке.
                                                                                                                  Это такой очень философский вопрос. Ассемблерный код для «передачи по ссылке» и «по значению через указатель» одинаковы.

                                                                                                                  Например, нельзя написать функцию, которая меняет местами аргументы
                                                                                                                  Объясните, пожалуйста, пожалуйста, что вы имеете в виду. Передача по ссылке в C++ даёт вам те же возможности, что и обычная передача для больгинства типов в Java. Вот только передать ссылку на int в Java нельзя — отсюда костыли…
                                                                                                                    +1

                                                                                                                    Вы заблуждаетесь.


                                                                                                                    Пример:


                                                                                                                    String foo = "foo";
                                                                                                                    String bar = "bar";
                                                                                                                    swap(foo, bar);
                                                                                                                    // здесь foo приняло значение "bar", а bar" приняло значение "foo".

                                                                                                                    В языке, где есть передача по ссылке, функцию swap написать можно, а в Java — нельзя.

                                                                                                                      0

                                                                                                                      Кстати, на правах рекламы, в rust это делается несколькими вариантами:


                                                                                                                      let (y, x) = (x, y); // фактически меняет только их имена
                                                                                                                                           // но мы можем так делать с разными типами
                                                                                                                      
                                                                                                                      // Или что-то такое
                                                                                                                      use std::mem::swap;
                                                                                                                      swap(&mut x, &mut y); // но типы должны быть одинаковыми
                                                                                                                      swap(x, y); // если x и y сами по себе ссылки
                                                                                                                      // при этом считается, что ссылки не перекрываются во имя оптимизаций конечно же

                                                                                                                      Доки на swap


                                                                                                                      Плюс там есть replace


                                                                                                                      Если нам нужно сделать сильное колдунство (например с перекрытием памяти у этих штук), то к нашим услугам такие же, но небезопасные ф-ии из модуля ptr.

                                                                                                                        0
                                                                                                                        Если нам нужно сделать сильное колдунство (например с перекрытием памяти у этих штук), то к нашим услугам такие же, но небезопасные ф-ии из модуля ptr.
                                                                                                                        Что, собственно, здесь и потребуется. Причём кончится это может тем, что вся ваша программа рассыпется к чертям собачьим.

                                                                                                                        Проблема не в перекрытии памяти, а в том, что строки в Java — immutable. Соответственно вам нужно будет в swap превратить неизменяемую ссылку на обьект в изменяемую. Да, это можно сделать через unsafe — но сольёт всю «прекрасную» безопасность rustа в унитаз. Или я ошибаюсь?

                                                                                                                        Тот факт, что в Java swap нереализуем, в rust — требует выхода за пределы «безопасного» подмножества языка, а в C++ — всего лишь пары castов — можно обсуждать… но никакого отношения к способу передачи (по ссылке или значению) это отношения не имеет.

                                                                                                                        Передайте в вашу функцию swap в Java вместо String (который менять нельзя) ArrayList (который менять таки можно) — и ваш swap преотлично реализуется…
                                                                                                                          0
                                                                                                                          Передайте в вашу функцию swap в Java вместо String (который менять нельзя) ArrayList (который менять таки можно) — и ваш swap преотлично реализуется…

                                                                                                                          Промутировать аргументы — это не то же самое, что поменять их местами. Имелась в виду тождественость ссылок после вызова swap, а не равенство по equals, разумеется.

                                                                                                                            0
                                                                                                                            Имелась в виду тождественость ссылок после вызова swap, а не равенство по equals, разумеется.


                                                                                                                            Ну, то есть, вы хотите следующего:
                                                                                                                            String foo = "foo";
                                                                                                                            String bar = "bar";
                                                                                                                            std::cout << "foo: " << &foo << "bar: " << &bar << "\n";
                                                                                                                            swap(foo, bar);
                                                                                                                            //  foo приняло значение "bar", а bar" приняло значение "foo".
                                                                                                                            // Потому следующая строка выведет то же, что и предыдущая.
                                                                                                                            std::cout << "foo: " << &bar << "bar: " << &foo << "\n";
                                                                                                                            
                                                                                                                            Дерзайте.

                                                                                                                            Проверить «тождественность ссылок» в Java нельзя… но в C++-то можно! И видно, что ни о какой «тождественности ссылок» речи не идёт.
                                                                                                                              0
                                                                                                                              Проверить «тождественность ссылок» в Java нельзя…

                                                                                                                              Мне даже немного неловко это писать. Но как это нельзя? А что == делает?


                                                                                                                              На sdt:swap вам уже указали и примеры привели. Честно говоря, мне кажется, всего этого должно быть достаточно, чтобы увидеть свою неправоту.


                                                                                                                              Демонстрация swap со строками
                                                                                                                              // Example program
                                                                                                                              #include <iostream>
                                                                                                                              #include <string>
                                                                                                                              
                                                                                                                              int main()
                                                                                                                              {
                                                                                                                                  std::string foo = "foo";
                                                                                                                                  std::string bar = "bar";
                                                                                                                                  std::cout << "foo: " << foo << " bar: " << bar << "\n";
                                                                                                                                  swap(foo, bar);
                                                                                                                                  std::cout << "foo: " << foo << " bar: " << bar << "\n";
                                                                                                                              }

                                                                                                                              Мутабельность std::string при этом ни при чем, потому что она не используется.


                                                                                                                              код std::swap
                                                                                                                              template<typename T> void swap(T& t1, T& t2) {
                                                                                                                                  T tmp(t1);
                                                                                                                                  t1=t2;
                                                                                                                                  t2=tmp;
                                                                                                                              }
                                                                                                                                0
                                                                                                                                Мне даже немного неловко это писать. Но как это нельзя? А что == делает?
                                                                                                                                Она сравнивает содержимое ссылок.

                                                                                                                                Мутабельность std::string при этом ни при чем, потому что она не используется.
                                                                                                                                Вы это серьёзно?

                                                                                                                                Код std::swap вы, кстати, примели неправильный. На самом деле используется std::swap<char, std::char_traits<char>, std::allocator<char>>, но даже если вы специализации не было… Что вторая строчка в приведённой вами функции делает?
                                                                                                                            0

                                                                                                                            Вы недостаточно знаете rust, чтоб судить о его недостатках и попросту заблуждаетесь. О текущих недостатках оного лучше читать что-то вроде https://github.com/rust-lang/rfcs/tree/master/text (некоторое, что там есть уже исправлено). Но это после чтения доков, спеков и относительно плотного знакомства.


                                                                                                                            Причём кончится это может тем, что вся ваша программа рассыпется к чертям собачьим.

                                                                                                                            При неаккуратном использовании. Как и в плюсах. Только в rust ещё и пометочка будет, что тут идёт сильное колдунство, о чём кстати и в документации есть. И без оной не скомпиляется.
                                                                                                                            Из документации: “trust me, I know what I’m doing.”. И нужно подобное редко.


                                                                                                                            Соответственно вам нужно будет в swap превратить неизменяемую ссылку на обьект в изменяемую.
                                                                                                                            Или я ошибаюсь?

                                                                                                                            Если нам требуется делать что-то тёмное с неизменяемыми штуками — у нас скорее всего серьёзная ошибка в дизайне. Ах, да. Строки rust не имеют ни какого отношения к строкам в java.
                                                                                                                            Или при реализации самого swap? Ну так то разумеется. А как иначе? Но это ведь часть стандартной библиотеки. Оттестировано и проверено.


                                                                                                                            Ещё по поводу строк в rust. Строка это тип str. Или тип &str, который есть ссылка на неизменяемый по размеру срез массива байт, который находится где-то в памяти плюс некоторое количество валидации для utf-8? Или который всё же &mut str, где мы можем изменять содержимое? А размер нам нужно менять? Тогда String, который в динамической памяти живёт. Сложно, да? Зато работает хорошо. Есть мутабельные и немутабельные для разных контекстов. Документация


                                                                                                                            в rust — требует выхода за пределы «безопасного» подмножества языка

                                                                                                                            Чем читаем? В rust есть безопасный швап и для чорной магии. Если нам просто два значения поменять местами — тот, что в mem используем. Если нужно что-то сложнее — это уже априорно чорная магия, которая требует аккуратности. И в этом случае unsafe будет подсказкой, что эту часть кода надо гораздо внимательнее писать и поддерживать.


                                                                                                                            Алсо о том, как контейнеры/ссылки себя в памяти ведут, есть такая штука https://docs.google.com/presentation/d/1q-c7UAyrUlM-eZyTo1pd8SZ0qwA_wYxmPZVOQkoDmH4/edit (на синенький текст ссылочки на документацию скастовали)

                                                                                                                              0
                                                                                                                              Вы недостаточно знаете rust, чтоб судить о его недостатках и попросту заблуждаетесь.
                                                                                                                              Где конкретно?

                                                                                                                              Строки rust не имеют ни какого отношения к строкам в java.
                                                                                                                              А где я говорил обратное?

                                                                                                                              Посмотрите на начало дискуссии: нам демонстрируют как std:swap меняет содержимое двух строк, после чего пафосно заявляют: В языке, где есть передача по ссылке, функцию swap написать можно, а в Java — нельзя.

                                                                                                                              На мои сначала робкие, а потом всё более настойчивые указания на то, что функция, подобная swap, вообще говоря, требует не только передачи обьектов по ссылке, но, кроме того требуется, чтобы эти обьекты были бы копируемыми (то есть изменяемыми), какомыми строки в Java не являются идёт «уход в несознанку», а потом, после дикого высера это работает именно потому, что передача идет по ссылке, а не потому, что int мутабелен и моего примера, который показывает, что это, мягко говоря, не так — следует заявление в известном духе.

                                                                                                                              Если нам требуется делать что-то тёмное с неизменяемыми штуками — у нас скорее всего серьёзная ошибка в дизайне.
                                                                                                                              А с этим, я собственно, и не спорю. Я-то надеялся, что когда я заставлю нашего д’Артаньяна применить const_cast можно будет поговорить о гарантиях безопасности (которая в C++ и Rust обходятся, а в Java — нет), но оказалось, что проблема была намного глубже: похоже автор искренне не понимает в чём разница между передачей параметров по значению и по ссылке.

                                                                                                                              Если нам просто два значения поменять местами — тот, что в mem используем. Если нужно что-то сложнее — это уже априорно чорная магия, которая требует аккуратности. И в этом случае unsafe будет подсказкой, что эту часть кода надо гораздо внимательнее писать и поддерживать.
                                                                                                                              Ну если исходить из заявления это работает именно потому, что передача идет по ссылке, а не потому, что int мутабелен — то нам-таки чёрная магия нужна. Что поменять местами две неизменяемые переменные-то!
                                                                                                                          0
                                                                                                                          Вы заблуждаетесь.
                                                                                                                          Серьёзно? Давайте пример до конца допишем, а потом уж говорить будем.

                                                                                                                          Пример:
                                                                                                                          String foo = "foo";
                                                                                                                          String bar = "bar";
                                                                                                                          swap(foo, bar);
                                                                                                                          // здесь foo приняло значение "bar", а bar" приняло значение "foo".
                                                                                                                          
                                                                                                                          А вы специально в примере используете не такие строки, как в Java? Давайте это исправим (реализация урезана, да, но идея, я думаю, понятна):
                                                                                                                          #include <string.h>
                                                                                                                          
                                                                                                                          #include <iostream>
                                                                                                                          
                                                                                                                          class String {
                                                                                                                           public:
                                                                                                                            String(const char* s) : data_(strdup(s)) {}
                                                                                                                            ~String() { free(const_cast<char*>(data_)); }
                                                                                                                            // Строки в Java immutable, имитирующие им C++ строки - тоже.
                                                                                                                            String operator=(String&&) = delete;
                                                                                                                            String operator=(const String&) = delete;
                                                                                                                            friend std::ostream& operator<<(std::ostream& o,
                                                                                                                                                            const String& s) {
                                                                                                                              o << s.data_;
                                                                                                                            }
                                                                                                                           private:
                                                                                                                            const char* data_;
                                                                                                                          };
                                                                                                                          
                                                                                                                          // Функию swap, пожалуйста.
                                                                                                                          
                                                                                                                          int main() {
                                                                                                                            String foo = {"foo"};
                                                                                                                            String bar = {"bar"};
                                                                                                                            swap(foo, bar);
                                                                                                                            // foo приняло значение "bar", а bar" приняло значение "foo".
                                                                                                                            std::cout << "foo: " << foo << "\n";
                                                                                                                            std::cout << "bar: " << bar << "\n";
                                                                                                                          }
                                                                                                                          

                                                                                                                          В языке, где есть передача по ссылке, функцию swap написать можно, а в Java — нельзя.
                                                                                                                          Прекрасно: допишите в мой пример свою функцию так, чтобы он компилировался и работал, потом — можно будет поговорить.
                                                                                                                            0
                                                                                                                            допишите в мой пример свою функцию так, чтобы он компилировался и работал
                                                                                                                            Эта функция уже реализована — std::swap:

                                                                                                                            int main() {
                                                                                                                              // в Java ведь с ссылками работаем, верно?
                                                                                                                              auto foo = std::make_shared< String >( "foo" );
                                                                                                                              auto bar = std::make_shared< String >( "bar" );
                                                                                                                              std::swap( foo, bar );
                                                                                                                              // foo приняло значение "bar", а bar" приняло значение "foo".
                                                                                                                              std::cout << "foo: " << *foo << "\n";
                                                                                                                              std::cout << "bar: " << *bar << "\n";
                                                                                                                            }
                                                                                                                            ideone.com/UZ75sr
                                                                                                                              0
                                                                                                                              Контрольный вопрос: в C для вас есть «передача по ссылке» или нет?

                                                                                                                              Потому что раз уж вы преврашаете std::swap(String&, String&) в std::swap(std::shared&, std::shared&) и заявляете — что это, просто синтаксис такой, на самом-то деле всё так же, как в Java, то и про C'шный вариант:
                                                                                                                                swap(&foo, &bar);
                                                                                                                              
                                                                                                                              можно сказать, что это — у нас передача по ссылке, а что там в вызове знаки & стоят — ну так это потому, что в C так принято…
                                                                                                                                0
                                                                                                                                Потому что раз уж вы преврашаете std::swap(String&, String&) в std::swap(std::shared&, std::shared&) и заявляете — что это, просто синтаксис такой, на самом-то деле всё так же, как в Java
                                                                                                                                Вы пытаетесь доказать свою точку зрения с помощью семантически разного кода. Я «превратил» этот код в адекватный Java-семантике.

                                                                                                                                можно сказать, что это — у нас передача по ссылке, а что там в вызове знаки & стоят — ну так это потому, что в C так принято…
                                                                                                                                Можно. Тогда соглашусь, что условно «передачей по ссылке» в Java можно считать костылики с одноэлементными массивами и прочими мутабельными обертками (= Возможно еще что-то из sun.misc.Unsafe (если еще не выпилили). Остальное все — передача по значению, ибо никакой другой возможности ссылаться на ссылки в Java нет.
                                                                                                                                  0
                                                                                                                                  Вы пытаетесь доказать свою точку зрения с помощью семантически разного кода. Я «превратил» этот код в адекватный Java-семантике.
                                                                                                                                  Проблема в том, что «передача по ссылке» vs «передача по значению» — это не о семантике. Это о синтаксисе.

                                                                                                                                  В частности, считается, что передачи по ссылке в C нет, а в C++ — есть. Но ведь легко убедиться, что C'шная void swap(int*, int*); и C++'ная void std(int&, int&); не просто «близкие родственники»! На уровне машинного кода они просто идентичны! Более того, при использовании ICF — это вообще будет одна и та же функция!

                                                                                                                                  Остальное все — передача по значению, ибо никакой другой возможности ссылаться на ссылки в Java нет.
                                                                                                                                  Что это за передача по значению такая, при которой обьект (если он, конечно, mutable) может быть испорчен? Хочу вам напомнить чем вообще эти два варианта отличаются: ри вызове по значению, выражение-аргумент вычисляется, и полученное значение связывается[en] с соответствующим формальным параметром функции (обычно посредством копирования этого значения в новую область памяти). При этом, если язык разрешает функциям присваивать значения своим параметрам, то изменения будут касаться лишь этих локальных копий, но видимые в месте вызова функции значения останутся неизменными по возвращении

                                                                                                                                  В Java при передаче изменяемых типов в функцию вы никогда не можете быть уверены, что она не испортит вам эту переменную — за исключением примитивных типов.

                                                                                                                                  Можно, конечно, «расщепить» типы данных и ссылки на эти типы данных и говорить о том, что ссылки передаются по значению… но учебники Java так не делают и, как уже говорилось выше, передача по значению отличается от передачи по ссылке в первую очередь синтаксически, а вот семантической разницы может и не быть (см. указатели в C и ссылки в C++).
                                                                                                                                    0
                                                                                                                                    Проблема в том, что «передача по ссылке» vs «передача по значению» — это не о семантике. Это о синтаксисе.
                                                                                                                                    Разница между объектом в стеке и указателем на объект в хипе очень даже семантическая.

                                                                                                                                    Что это за передача по значению такая, при которой обьект (если он, конечно, mutable) может быть испорчен?
                                                                                                                                    По значению вы передаете ссылку, которая копируется. Поэтому ссылку повредить/переназначить вы не сможете никак. В родственном C# для этого есть ref/out-модификаторы, что подчеркивают эту разницу. В Java же распространенной практикой (по крайней мере Хорстман с Кеем об этом пишут) является обёртывание объекта в массив единичной длины.

                                                                                                                                    Можно, конечно, «расщепить» типы данных и ссылки на эти типы данных и говорить о том, что ссылки передаются по значению… но учебники Java так не делают
                                                                                                                                    Потому что это учебники про язык, а не про платформу.
                                                                                                                                      0
                                                                                                                                      Потому что это учебники про язык, а не про платформу.

                                                                                                                                      На самом деле учебники, несомненно, "так делают", т.е. различают объекты и ссылки (включая учебники начального уровня, например, Head First).


                                                                                                                                      Более того, это в явном виде написано по ссылке выше ("… в сообществах Java и Visual Basic ту же семантику часто описывают как «вызов по значению, где „значением“ является ссылка на объект»...").

                                                                                                                                        0
                                                                                                                                        Разница между объектом в стеке и указателем на объект в хипе очень даже семантическая.
                                                                                                                                        Да, но вопрос передачи аргументов по ссылке или значению — он немного ортогонален, хотя в Java они связаны: все обьекты, размещённые в стеке передаются по значению, все обьекты, размещённые в куче — по ссылке.

                                                                                                                                        В C++ — это не так, можно передавать по значению как обьекты размещённые в стеке, так и обьекты, размещённые в куче — и по ссылке тоже можно передавать и те и другие.

                                                                                                                                        Но и в Java и в C++ для функции, подобной swap мало того, чтобы обьект был передан по ссылке — нужно ещё, чтобы он был изменяем!
                                                                                                                                          0
                                                                                                                                          в Java и в C++ для функции, подобной swap мало того, чтобы обьект был передан по ссылке — нужно ещё, чтобы он был изменяем!
                                                                                                                                          Если мы хотим изменить состояние объекта, то нельзя. Но если мы хотим поменять местами объекты (в чем и кроется смысл swap), то в C++ это делается запросто чистыми синтаксическими средствами, в Java — только неочевидными хаками с целью преодолеть и превозмочь.
                                                                                                                                            +1
                                                                                                                                            Но если мы хотим поменять местами объекты (в чем и кроется смысл swap)
                                                                                                                                            Нет, нет и нет.

                                                                                                                                            Вот тут уже даже открыли почти все буквы, но не смогли прочитать слово. std::swap(int&, int&), скажем, делает следующее:

                                                                                                                                            1. Создаёт временный обьект типа int.
                                                                                                                                            2. Копирует значение первого аргумента в этот временный обьект.
                                                                                                                                            3. Копирует значение второго аргумента в первый.
                                                                                                                                            4. Копирует значение временного обьекта во второй аргумент.
                                                                                                                                            в C++ это делается запросто чистыми синтаксическими средствами, в Java — только неочевидными хаками с целью преодолеть и превозмочь
                                                                                                                                            Это как? Это хде? Единственное отличие C++ от Java — в том, что для всяких обьектов типа std::string определён operator=, который замещает содержимое обьекта содержимым другого, родственного по типу, обьекта.

                                                                                                                                            Заведите интерфейс Assignable в Java с функцией Assign — и будет вам swap для. Вот прям такой же, как в C++. В точности.

                                                                                                                                            Какое вообще имеет отношение наличие метода operator= в классе std::basic_string и отсутствие аналогичного метода в неизменяемом классе String к способу передачи параметров???

                                                                                                                                            На самом деле сакральный смысл существования функции std::swap не в том, чтобы избежать копирования, скажем, int'ов (это и не нужно и невозможно). Нет — фишка в другом: специализации std::swap (скажем std::swap(std::basic_string)) могут не создавать временный обьект и не копировать всё содержимое (в частности std::swap(std::basic_string) вызывает std::basic_string::swap, а та уже, являясь функцией обьекта, может добраться до его содержимого и «дёшево» переставить указатели, вместо того, чтобы «дорого» копировать строки). Опять-таки вся эта деятельность может быть в точности возспроизведена в Java и, если бы карты легли иначе и, кроме интерфейса Cloneable Java имела бы и похожий интерфейс Assignable, то все эти чудеса можно было бы воспроизвести точь-в-точь в Java. Хотите — сделайте свою библиотеку с классами CppStyleString и функций Swap, определённой для неё. В языке для этого ничего менять не потребуется.
                                                                                                                                              0
                                                                                                                                              Это понятно, мутаторную форму std::swap для std::basic_string мы условились не использовать.

                                                                                                                                              Но сути не меняет: в Java строки — это объект ссылочный, полностю лежащий в хипе. Поэтому хорошего аналога String foo = {"foo"}; там не сделать. Ну вообще никак. (Более того, сами строки размером до sizeof(_CharT*) в типичных имплементациях аллоцируются на стеке) Поэтому просто ссылки не катят. Нам нужны указатели и полностью хиповый объект! С чего мы и начали этот длинный тред.
                                                                                                                                                –2
                                                                                                                                                Это понятно, мутаторную форму std::swap для std::basic_string мы условились не использовать.
                                                                                                                                                Тем не менее с неё и начался весь этот субтред.

                                                                                                                                                Поэтому просто ссылки не катят. Нам нужны указатели и полностью хиповый объект! С чего мы и начали этот длинный тред.
                                                                                                                                                Нет. Нужны ссылки. Союственно «иностранное» название call-by-reference как бы намекает.

                                                                                                                                                Полным аналогом версии из Java в C++ будет следующее:
                                                                                                                                                const std::string& foo = std::string("foo");
                                                                                                                                                const std::string& bar = std::string("bar");
                                                                                                                                                std::swap(foo, bar);
                                                                                                                                                

                                                                                                                                                И, сюрприз, сюрприз, сюрприз: это — тоже не работает. Даже не компилируется.
                                                                                                                                                  0
                                                                                                                                                  Тем не менее с неё и начался весь этот субтред.
                                                                                                                                                  Краткий экскурс по треду, для тех, кто только пришел: я поправил человека и даже как-то косвенно говорил о том, что он был не прав. Далее я привел код, с которым мой оппонент так же не был согласен.

                                                                                                                                                  Полным аналогом версии из Java в C++ будет следующее
                                                                                                                                                  У вас мутабельный объект в стеке. Попробуйте еще раз.
                                                                                                                                                    0
                                                                                                                                                    Нет. Нужны ссылки. Союственно «иностранное» название call-by-reference как бы намекает.
                                                                                                                                                    Там call-by-reference и происходит) Указатели передаются по ссылке. Только в Java «безопасные указатели» называются ссылками.
                                                                                                                                              0
                                                                                                                                              Да, но вопрос передачи аргументов по ссылке или значению — он немного ортогонален, хотя в Java они связаны: все обьекты, размещённые в стеке передаются по значению, все обьекты, размещённые в куче — по ссылке.

                                                                                                                                              В Java все переменные передаются по значению. Только значение переменных, указывающих на объект это, как несложно догадаться, указатель :)

                                                                                                                                                0
                                                                                                                                                В этом случае у вас вообще ни в каком языке передачи значений по ссылке не будет. Ибо версия на C++ тоже принимает не обьекты, а ссылки на объекты (вот тут даже её код в три строки приведён) и она эти ссылки не меняет (собственно в C++ и нет вообще никаких методов, позволяющих изменять ссылки).

                                                                                                                                                Что гораздо хуже — в языках типа Algol'а и Pascal'я, откуда пошли эти термины («вызов по ссылке» и «вызов по значению») в функцию, которая описывает параметр не как x : Integer, а как var x : Integer тоже передаётся не обьект, а ссылка.

                                                                                                                                                Рассмотрите следущий код для языка Pascal (учили в школе, аль нет?):
                                                                                                                                                procedure foo(var a : String, var b : string);
                                                                                                                                                begin
                                                                                                                                                  swap(a, b);
                                                                                                                                                end;
                                                                                                                                                

                                                                                                                                                Рассмотрите этот пример. Это — самое эталонное, самое «true», «лошадь ростом в метр и весом в один килограмм» pass-by-reference. То, с чего пошла вся терминология. До того, как в языка программирования появилась куча и даже стек (да-да — в ранних языках программирования стека не было).

                                                                                                                                                И что же мы тут видим? Правильно: мы видим две ссылки на объекты типа String, которые при вызове функции swap копируются — после чего функция swap их изменять не может, но может изменять то, на что они указывают!

                                                                                                                                                Почему, блин, вещь, которая полвека назад называлась pass-by-reference, транслируясь почти в такой же байткод как в Java (да-да, вы не поверите, но Pascal тоже транслировался в байткод, как и предшественник C, BCPL) стала вдруг называться «pass-by-value». С какого, я извиняюсь, перепугу?
                                                                                                                                                  0
                                                                                                                                                  В этом случае у вас вообще ни в каком языке передачи значений по ссылке не будет. Ибо версия на C++ тоже принимает не обьекты, а ссылки на объекты (вот тут даже её код в три строки приведён) и она эти ссылки не меняет (собственно в C++ и нет вообще никаких методов, позволяющих изменять ссылки).

                                                                                                                                                  Вот вам код на C++, демонстрирующий, что есть в Java, а чего нет


                                                                                                                                                  Код под спойлером
                                                                                                                                                  #include <iostream>
                                                                                                                                                  
                                                                                                                                                  using namespace std;
                                                                                                                                                  
                                                                                                                                                  class TestStruct {
                                                                                                                                                      public:
                                                                                                                                                      int id;
                                                                                                                                                      int count;
                                                                                                                                                  
                                                                                                                                                      TestStruct(int id, int count) {
                                                                                                                                                          this->id = id;
                                                                                                                                                          this->count = count;
                                                                                                                                                      }
                                                                                                                                                  
                                                                                                                                                      TestStruct(const TestStruct& obj) {
                                                                                                                                                          this->id = obj.id;
                                                                                                                                                          this->count = obj.count;
                                                                                                                                                          cout <<"copy constructor working " << std::endl;
                                                                                                                                                      } 
                                                                                                                                                  };
                                                                                                                                                  
                                                                                                                                                  int main()
                                                                                                                                                  {
                                                                                                                                                      {
                                                                                                                                                          TestStruct s1(1,1);
                                                                                                                                                          TestStruct s2(2,2);
                                                                                                                                                  
                                                                                                                                                          cout <<"copy constructor will be invoked, java can do something like that" << std::endl;
                                                                                                                                                          std::swap(s1, s2);
                                                                                                                                                  
                                                                                                                                                           //Java can do something like that
                                                                                                                                                          cout <<"s1.id should be 2 and is " << s1.id << std::endl;
                                                                                                                                                      }
                                                                                                                                                  
                                                                                                                                                      {
                                                                                                                                                      TestStruct* s1 = new TestStruct(1,1);
                                                                                                                                                      TestStruct* s2 = new TestStruct(2,2);
                                                                                                                                                  
                                                                                                                                                      cout <<"References will be copied, java can't do that" << std::endl;
                                                                                                                                                       //Java can't do that
                                                                                                                                                      std::swap(s1, s2);
                                                                                                                                                  
                                                                                                                                                      cout <<"s1->id  should be 2 and is " << s1->id << std::endl;
                                                                                                                                                      }
                                                                                                                                                  
                                                                                                                                                      return 0;
                                                                                                                                                  }

                                                                                                                                                  В джаве переменные с объектами — указатели, которые, как и всё остальное передаются по значению, вот что я имею в виду.

                                                                                                                                                    –1
                                                                                                                                                    В джаве переменные с объектами — указатели, которые, как и всё остальное передаются по значению, вот что я имею в виду.
                                                                                                                                                    Передать «ссылку на ссылку» в Java действительно нельзя — но какое это имеет значение? Обьект-то передаётся по ссылке!

                                                                                                                                                    P.S. На самом деле в Wikipedia всё описано. Стратегия передачи параметров в Java (JavaScript, Python, далее везде) имеет отдельное имя: Вызов по соиспользованию (call by sharing).

                                                                                                                                                    Видимо для того, чтобы, наконец, прекратить эту дискуссию… потому что некоторые языки называют «это» вызов-по-значению, а некоторые вызов-по-ссылке… несмотря на то, что семантика одинакова!
                                                                                                                                    0
                                                                                                                                    А вы специально в примере используете не такие строки, как в Java?

                                                                                                                                    Не понял, что вы имеете в виду. Приведенный (невозможный) код написан на Java.


                                                                                                                                    Дописывать и вообще разбирать ваш код мне неудобно и недосуг, извините. Вот (найденный) код с использованием std::swap:


                                                                                                                                    #include <iostream>
                                                                                                                                    
                                                                                                                                    using namespace std;
                                                                                                                                    int main()
                                                                                                                                    {
                                                                                                                                        int a, b;
                                                                                                                                        cin >> a;
                                                                                                                                        cin >> b;
                                                                                                                                        swap(a, b);
                                                                                                                                        cout << a;
                                                                                                                                        cout << b;
                                                                                                                                        return(0);
                                                                                                                                    }

                                                                                                                                    В Java так сделать нельзя, что с int, что с Integer.


                                                                                                                                    Повторюсь, если вы думаете, что в Java агрументы передаются по ссылке, вы заблуждаетесь, причем заблуждаетесь капитально. Рекомендую погуглить что-то вроде "is Java pass-by-value". Например, на Stackoverflow это подробно разобрано. Ну или вот (часть 8.4.1 спецификации Java 8):


                                                                                                                                    When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables...
                                                                                                                                      0
                                                                                                                                      Я боюсь это становится вопросом терминологии. Можно либо считать, что в Java всё и всегда передаётся по ссылке, но взять «ссылку на ссылку» нельзя, потому что обьекты, размещённые на стеке, недоступны GC, либо разделять обьекты (хранящиеся в куче) и ссылки на них (размещённые на стеке).

                                                                                                                                      В первом случае — параметры у нас таки передаются по ссылке, но агрументом является обьект String (как, собственно, в коде и написано), либо, альтернативно, что есть ещё и ссылки где-то (которых в коде, в общем-то, не видно, они для нас как тот «суслик») — тогда передача происходит по значению, но всё окончательно запутывается.
                                                                                                                                        –1

                                                                                                                                        Судя по тому, что вы написали выше ("Передача по ссылке в C++ даёт вам те же возможности, что и обычная передача для больгинства типов в Java."), у вас была содержательная, а не терминологическая ошибка в картине мира.


                                                                                                                                        А что до терминологии, то она вполне стандартна, и "считать, что в Java всё и всегда передаётся по ссылке" нельзя.

                                                                                                                                          0
                                                                                                                                          у вас была содержательная, а не терминологическая ошибка в картине мира.
                                                                                                                                          Извините, но что-то не так в вашей картине мира, а не в моей. Ибо заявление:
                                                                                                                                          то работает именно потому, что передача идет по ссылке, а не потому, что int мутабелен
                                                                                                                                          это что-то за гранью добра и зла.
                                                                                                                                        0
                                                                                                                                        В Java так сделать нельзя, что с int, что с Integer.
                                                                                                                                        В Java так сделать нельзя, не потому, что Integer передаётся по значению, а потому что он Immutable. Mutable вариант — это, например int[] с одним элементом.

                                                                                                                                        Не понял, что вы имеете в виду.
                                                                                                                                        Во всех ваших примерах на Java вы используете immutable типы. И изменить их нельзя не потому, что они «переданы по значению», а потому что они, в принципе, неизменяемы.

                                                                                                                                        В моём примере String — тоже неизменяемый и, внезапно, его «так просто» изменить нельзя — даже при передаче по ссылке.
                                                                                                                                          0

                                                                                                                                          Изменяемость типа с этими вопросами не связана, см. другой мой коммент. К инстансу ArrayList указанные аргументы применимы в равной степени.


                                                                                                                                          std::swap именно меняет ссылки, а не изменяет каждое из значений. В приведенном мной коде, кстати, int. И это работает именно потому, что передача идет по ссылке, а не потому, что int мутабелен.

                                                                                                                                            0
                                                                                                                                            И это работает именно потому, что передача идет по ссылке, а не потому, что int мутабелен.
                                                                                                                                            В вашей программе обьявить их иммутабельными нельзя, но можно её немного модифицировать — и всё. std::swap перестаёт работать.

                                                                                                                                            Ещё раз, для идиотов. Для работоспособности функций, подобных std::swap нужно выполнение не одного, двух условий:

                                                                                                                                            1. Передача аргументов в функцию должна происходить не по значению, а по ссылке.
                                                                                                                                            2. Переданные значения не должны быть immutable (для них должен быть определён operator=).

                                                                                                                                            Только при выполнении обоих условий функция, подобная std::swap реализуема. Для примитивных типов в Java не выполняется первое условие, для типов Integer и String — второе, но возьмите ArrayList — и всё получится!
                                                                                                                                              0
                                                                                                                                              Ещё раз, для идиотов.

                                                                                                                                              Уверен, что вы кругом неправы в основах, но разговор окончен.

                                                                                                                        0
                                                                                                                        Ну хоть бы взять пример выше — LINQ позволяет сделать код куда компактнее, чище, проще для понимания, но ухудшает эффективность.

                                                                                                                        В чем LINQ ухудшает эффективность? Когда он плохо в sql смаплен?
                                                                                                                          +2

                                                                                                                          Если говорить про Linq-to-Objects — многовато лишних аллокаций.

                                                                                                                            0
                                                                                                                            Кстати, тут на днях появилось (сам еще толком не смотрел) github.com/kevin-montrose/LinqAF
                                                                                                                              0
                                                                                                                              Только большинству приложений это по барабану.
                                                                                                                          –2
                                                                                                                          Спорное мнение. В итоге производительность программы теряется в угоду усиленной читабельности кода.
                                                                                                                            +6

                                                                                                                            Во-первых, не всегда. Во-вторых — ну да, иногда теряется. Это далеко не всегда настолько важно.

                                                                                                                              +9
                                                                                                                              производительность процессоров растет быстрее, чем производительность людей.
                                                                                                                              В тех 7% где не растет — будет не тупой код, и комментарий «не трогайте тут, выигрываем несколько тактов»
                                                                                                                                0
                                                                                                                                Ну, как совет при оформлении PR в ASP.NET Core, пишут в гайдлайнах избегать Linq в hot-path частях.
                                                                                                                                  0
                                                                                                                                  Потому что там это имеет смысл. Но подавляющему большинству приложений далеко до ASP.NET Core в плане «горячности» hot path'ов. А каким-то это и вовсе неважно.
                                                                                                                                  0

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

                                                                                                                                    +3
                                                                                                                                    Это только так кажется.
                                                                                                                                    На самом деле ровно наоборот.
                                                                                                                                    Именно «умные» программы как правило и тормозят, поскольку по мере роста всю картинку не видит никто, и начинается нагромождение на нагромождение и так далее.
                                                                                                                                    А простая структура, в которой каждый элемент прост и «понятен даже идиоту», там и доработать узкое место проще.
                                                                                                                                    В сферическом проекте где время бесконечно — конечно лучше оптимизировать всё. А в реальном — всё что ты потратишь на преждевременную нанооптимизацию тебе придется откуда-то взять. И либо придется пожертвовать (выпустить много позже) фунционалом, либо не оптимизировать именно то что нужно.
                                                                                                                                      0
                                                                                                                                      Именно «умные» программы как правило и тормозят, поскольку по мере роста всю картинку не видит никто, и начинается нагромождение на нагромождение и так далее.
                                                                                                                                      Это решается абстракциями. Микрооптимизации на то и микро, что на общую архитектуру не влияют и живут в своих четко очерченных, хорошо закоментированных областях.
                                                                                                                                        0

                                                                                                                                        Абстракции увеличивают тормоза частенько :)

                                                                                                                                          0
                                                                                                                                          Вообще любой код увеличивает тормоза) Но есть же умный компилятор и здравый смысл.
                                                                                                                                      0
                                                                                                                                      не понимаю в чем проблема.

                                                                                                                                      Если при написании программы, у вас спрашивали требования (нужно что бы быстро, нужно что бы несколько штук одновременно), то значит, нужно идти к авторам и тыкать пальцем «вот тут не соответствует».
                                                                                                                                      Если же это массовый продукт, то видимо есть некий механизм, для обратной связи, и можно верить, что этот механизм рабочий.

                                                                                                                                      Чудес, к сожалению, в этом месте не бывает. Вот, у меня в списке дежурных фраз есть
                                                                                                                                      Тупые решения выигрывают у умных в 9 из 10 случаев. Будьте достаточно умны, что бы предлагать тупое решение

                                                                                                                                      Практически вся эта статья в одной фразе.
                                                                                                                                      0
                                                                                                                                      Ну вот я обновил 3770k на 8700k — по бенчмаркам разница 2x. Это 6 лет прошло. С одной стороны за 6 лет новичок вполне обучается в опытного разработчика и его производительность более чем удваивается. С другой стороны дополнительных абстракций в софт за 6 лет добавлено вполне достаточно, чтобы двукратный рост производительности процессоров нейтрализовать. И это если не считать ущерб от meltdown.
                                                                                                                                        0

                                                                                                                                        Так-то да, а потом ты запускаешь Atom на ноутбуке старше 3х лет и начинаются боль и страдания.

                                                                                                                                        +5

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


                                                                                                                                        До середины 90-х нам иногда приходилось оптимизировать и коэффициент k в алгоритмах с линейной сложностью O(kN), но и тогда, когда компьютеры были бледнее "Малины", кроме того, что такие приемы были редки и очевидны — очень важно было следить за "внятностью речи".

                                                                                                                                          0
                                                                                                                                          Архитектура — это основа читабельности. И именно в ней чаще всего приходится жертвовать читабельность.
                                                                                                                                            0
                                                                                                                                            Архитектура приложения — это первое, что не выдерживает столкновения с реальностью.
                                                                                                                                          +1
                                                                                                                                          Производительность программы действительно бывает важна обычно всего в нескольких местах, которые лучше оформить как отдельный чёрный ящик.
                                                                                                                                            0
                                                                                                                                            Круто, если в приложении производительность зависит от алгоритма, который легко отделяется в черный ящик. Хуже, когда этот алгоритм через весть проект идет.
                                                                                                                                              +2
                                                                                                                                              Неее. Нормально когда ЛЮБАЯ часть приложения превращается в черный ящик и все приложение состоит из черных ящиков (которые впрочем на самом деле белые).
                                                                                                                                              И кошмар когда этого нельзя сделать.
                                                                                                                                              Вроде смысл не сильно меняется, но акценты именно так стоят ибо как правило невозможность разнести в черные ящики это проблема архитектуры.
                                                                                                                                                0
                                                                                                                                                Т.е. кошмар — это всегда.
                                                                                                                                            0

                                                                                                                                            Тупой код обычно состоит из каких-то стандартных паттернов и стандартных приёмов. Таких приёмов, которые умеют находить и распознавать и оптимизировать компиляторы, интерпретаторы и JIT.

                                                                                                                                            –2
                                                                                                                                            но совершенствоваться тоже ведь нужно… не даром придуманы всякие конструкции?
                                                                                                                                              +20

                                                                                                                                              "Совершенствование" состоит как раз в том, чтобы понимать, когда "всякие конструкции" надо применять, а когда — нет.

                                                                                                                                                0
                                                                                                                                                Ну тогда уж и про связность надо упомянуть.
                                                                                                                                                Не совсем про простоту и «глупость», но если не иметь достаточного опыта и начинать снижать зацепление, то легко можно и связность понизить, так что лучше когда они вместе ходят.
                                                                                                                                                  0
                                                                                                                                                  Вся статья собственно говоря как раз про KISS
                                                                                                                                                  +5
                                                                                                                                                  в прошлом месяце поймал себя на мысли: сделать просто — сложно.

                                                                                                                                                  этот крутой чувак, из мира Java, кажется говорил не про метод использование if, switch, etc., а про метод реализации конкретных алгоритмом, реализация которых в чистом коде дает понять при чтении: это функция f, они принимает аргумент x и возвращает y, и в тупом коде ясно как день без лишних комментариев каким образом c x сделался y.

                                                                                                                                                  … другой вопрос — именование, не менее сложная задача чем писать простой код…

                                                                                                                                                  да и вообще, одна из любимых фраз: простые вещи ломаются реже сложных.
                                                                                                                                                    0
                                                                                                                                                    Искусство хорошего именования — часть искусства написания хорошего кода.
                                                                                                                                                      0
                                                                                                                                                      Очень важная часть! Naming things and cache coherency are the hardest problems in CS. :-)
                                                                                                                                                    +13
                                                                                                                                                    А называю это не «тупой», а «скучный» код. Код в котором нет никаких неожиданностей, ничего неочевидного, нет никаких крутых финтов, никаких исключений из правил, никаких нарушений архитектурного шаблона, никаких сложных абстракций, код, который может понять даже человек не знакомый с этим конкретным языком программирования.
                                                                                                                                                      +5
                                                                                                                                                      код, который может понять даже человек не знакомый с этим конкретным языком программирования
                                                                                                                                                      Не к этому ли нужно стремиться?
                                                                                                                                                        0
                                                                                                                                                        код, который может понять даже человек не знакомый с этим конкретным языком программирования
                                                                                                                                                        Не к этому ли нужно стремиться?

                                                                                                                                                        Вряд ли к этому.


                                                                                                                                                        Допустим, мы пишем чистый и понятный код.
                                                                                                                                                        При этом к месту используем лямбды, LINQ (C#) или Stream API (Java).
                                                                                                                                                        Но ведь до сих пор много разработчиков не освоили функциональный подход, хотя он есть в C# аж лет 10, и почти 4 года в Java.
                                                                                                                                                        Что же, нам не использовать его, чтобы все могли прочитать?

                                                                                                                                                          0
                                                                                                                                                          Понять что есть лямбды нужно один раз, и дальше этот разработчик вполне будет читать код, так что код будет все еще прост. А вот всякие нагромождения тернарных операторов в тернарных операторах, или десятки параметров метода на километр — когнитивную нагрузку создают очень значительную, и каждый раз когда встречаются, и неважно что концепция разработчику знакома. Я бы уточнил формулировку из комментария выше:
                                                                                                                                                          код, который может понять даже человек не знакомый с этим конкретным языком программирования
                                                                                                                                                          , в случае знания концепций с использованием которых он был написан.
                                                                                                                                                            0
                                                                                                                                                            Давайте оставим солонку уязвимой а общипанную курицу — человеком. Ну и так же ясно о чем речь). А то сейчас добавим «и при знании основ синтаксиса»… потом отрефакторим, добавим, уберем, опять добавим, опять перепишем и покроем тестами…