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

Предлагаю читателям «Хабрахабра» перевод публикации «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:

«Всегда кодируй так, будто парень, который будет поддерживать твой код — необузданный психопат, и он знает, где ты живёшь».
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 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>

                • 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
                                В C до C99 не было bool.
                                • +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
                                                                                        Сеньором он становится будет в другом месте.

                                                                                        И ведь станет!
                                                                                  • +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 нет.