Даже в тех языках, где у вас есть явные манипуляции с указателями, такие как C, они всегда передаются по значению (вы можете передавать их по ссылке, но это не поведение по умолчанию).
Какова польза от этого, почему так много языков передаются значениями и почему другие передаются по ссылке ? (Я понимаю, что Haskell передается по ссылке, хотя я не уверен).
programming-languages
language-design
В моем коде нет ошибок
источник
источник
void acceptEntireProgrammingLanguageByValue(C++);
temp := a; a := b; b := temp;
И когда она вернется, значенияa
иb
будут поменяны местами. Там нет никакого способа сделать это в C; Вы должны передавать указатели наa
иb
иswap
рутина должна действовать на значения, на которые они указывают.Ответы:
Передача по значению часто безопаснее, чем передача по ссылке, потому что вы не можете случайно изменить параметры вашего метода / функции. Это упрощает использование языка, поскольку вам не нужно беспокоиться о переменных, которые вы передаете функции. Вы знаете, что они не будут изменены, и это часто то, что вы ожидаете .
Тем не менее, если вы хотите изменить параметры, вам нужно выполнить некоторую явную операцию, чтобы прояснить это (передать указатель). Это заставит всех ваших абонентов сделать вызов немного по-другому (
&variable
в C), и это сделает явным, что параметр variable может быть изменен.Так что теперь вы можете предположить, что функция не изменит параметр вашей переменной, если она не помечена для этого явным образом (требуя передать указатель). Это более безопасное и чистое решение, чем альтернатива. Предположим, что все может изменить ваши параметры, если они прямо не скажут, что не могут.
источник
Call-by-value и call-by-reference - это методы реализации, которые давно были приняты за режимы передачи параметров.
В начале был Фортран. У FORTRAN был только вызов по ссылке, поскольку подпрограммы должны были иметь возможность изменять свои параметры, а вычислительные циклы были слишком дорогими, чтобы разрешать множественные режимы передачи параметров, плюс было недостаточно известно о программировании, когда был впервые определен FORTRAN.
Алгол придумал вызов по имени и вызов по значению. Вызов по значению был для вещей, которые не должны были быть изменены (входные параметры). Вызов по имени был для выходных параметров. Обращение по имени оказалось крупным черепком, и АЛГОЛ 68 сбросил его.
PASCAL предоставил вызов по значению и вызов по ссылке. Это не дало программисту никакого способа сообщить компилятору, что он передает большой объект (обычно массив) по ссылке, чтобы избежать перебора стека параметров, но что объект не должен изменяться.
PASCAL добавил указатели в лексикон языкового дизайна.
C предоставил вызов по значению и смоделировал вызов по ссылке, определив оператор kludge для возврата указателя на произвольный объект в памяти.
Более поздние языки копировали C, в основном потому, что дизайнеры больше ничего не видели. Вероятно, поэтому так важен call-on-value.
C ++ добавил Kludge поверх C-Kludge, чтобы обеспечить вызов по ссылке.
Теперь, как прямой результат «вызов по значению», «вызов по ссылке» и «вызов по указателю-kludge», C и C ++ (программисты) испытывают ужасные головные боли с указателями на const и указателями на const (только для чтения) объекты.
Аде удалось избежать всего этого кошмара.
Ада не имеет явного вызова по значению против вызова по ссылке. Скорее, Ада имеет входящие параметры (которые могут быть прочитаны, но не записаны), выходные параметры (которые ДОЛЖНЫ быть записаны до того, как их можно будет прочитать) и выходные параметры, которые могут быть прочитаны и записаны в любом порядке. Компилятор решает, будет ли определенный параметр передан по значению или по ссылке: он прозрачен для программиста.
источник
In the beginning, there was FORTRAN
.0
префикс несовместим с любым другим префиксом неосновной десятки. Это может быть несколько извиняющим в C (и в основном в исходно-совместимых языках, например, C ++, Objective C), если восьмеричная была единственной альтернативной базой при представлении, но когда более современные языки используют и то,0x
и другое0
с самого начала, это просто заставляет их выглядеть плохо продуманный.Передача по ссылке учитывает очень тонкие непреднамеренные побочные эффекты, которые очень трудно или почти невозможно отследить, когда они начинают вызывать непреднамеренное поведение.
Проходим по значению, особенно
final
,static
илиconst
входные параметры делают весь этот класс ошибки исчезают.Неизменяемые языки еще более детерминированы и их легче рассуждать и понимать, что происходит и что ожидается от функции.
источник
Swap
хаки, которые не используют временную переменную, хотя сами по себе вряд ли будут проблемой, показывают, насколько сложным может быть отладка более сложного примера.Смысл разбивки больших программ на маленькие подпрограммы заключается в том, что вы можете самостоятельно рассуждать о подпрограммах. Передача по ссылке нарушает это свойство. (Как и общее изменяемое состояние.)
На самом деле, C всегда передается по значению, а не по ссылке. Вы можете взять адрес чего-либо и передать этот адрес, но адрес все равно будет передаваться по значению.
Существует две основные причины использования передачи по ссылке:
Лично я считаю, что № 1 - фальшивка: это почти всегда оправдание плохого API и / или языкового дизайна:
Вы также можете смоделировать несколько возвращаемых значений, упаковав их в некоторую облегченную структуру данных, такую как кортеж. Это работает особенно хорошо, если язык поддерживает сопоставление с образцом или деструктурирование связывания. Например, Руби:
Часто вам даже не нужно многократные возвращаемые значения. Например, один из популярных шаблонов заключается в том, что подпрограмма возвращает код ошибки, а фактический результат записывается обратно по ссылке. Вместо этого вы должны просто сгенерировать исключение, если ошибка является неожиданной, или вернуть ее,
Either<Exception, T>
если ошибка ожидается. Другой шаблон - возвращать логическое значение, которое сообщает, была ли операция успешной, и возвращать фактический результат по ссылке. Опять же, если сбой был неожиданным, вы должны вместо этого выдать исключение, если сбой ожидается, например, при поиске значения в словаре, вы должны вернутьMaybe<T>
вместо него.Передача по ссылке может быть более эффективной, чем передача по значению, потому что вам не нужно копировать значение.
Нет, Haskell не передается по ссылке. И при этом это не передача по стоимости. Передача по ссылке и передача по значению являются строгими стратегиями оценки, но Haskell не является строгим.
На самом деле, спецификация Haskell не определяет какую-либо конкретную стратегию оценки. Большинство реализаций Hakell используют смесь вызовов по имени и вызова по необходимости (вариант вызова по имени с запоминанием), но стандарт этого не требует.
Обратите внимание, что даже для строгих языков не имеет смысла проводить различие между передачей по ссылке или передачей по значению для функциональных языков, поскольку различие между ними может наблюдаться только в случае изменения ссылки. Таким образом, разработчик может свободно выбирать между ними, не нарушая семантику языка.
источник
Поведение зависит от модели вызова языка, типа аргументов и моделей памяти языка.
При использовании простых нативных типов передача по значению позволяет передавать значение по регистрам. Это может быть очень быстро, так как значение не нужно ни загружать из памяти, ни сохранять обратно. Подобная оптимизация также возможна просто путем повторного использования памяти, используемой аргументом, как только вызываемый объект завершил работу, не рискуя связываться с копией объекта вызывающей стороны. Если бы аргумент был временным объектом, вам, вероятно, следовало бы сохранить полную копию (C ++ 11 делает этот вид оптимизации еще более очевидным с новой правой ссылкой и ее семантикой перемещения).
Во многих ОО-языках (в данном контексте C ++ является скорее исключением) вы не можете передать объект по значению. Вы вынуждены передать его по ссылке. Это делает код полиморфным по умолчанию и в большей степени соответствует представлению об экземплярах, соответствующих OO. Кроме того, если вы хотите передать по значению, вы должны сделать копию самостоятельно, признавая стоимость производительности, которая сгенерировала такое действие. В этом случае язык выбирает для вас подход, который, скорее всего, даст вам наилучшую производительность.
В случае функциональных языков, я думаю, передача по значению или ссылке - это просто вопрос оптимизации. Поскольку функции в таком языке чистые и не имеют побочных эффектов, на самом деле нет смысла копировать значение, кроме скорости. Я даже почти уверен, что такой язык часто использует одну и ту же копию объектов с одинаковыми значениями, возможность доступна только в том случае, если вы используете проходную (постоянную) ссылочную семантику. Python также использовал этот прием для целочисленных и общих строк (таких как методы и имена классов), объясняя, почему целое число и строки являются постоянными объектами в Python. Это также помогает снова оптимизировать код, позволяя, например, сравнение указателей вместо сравнения содержимого и выполнять ленивую оценку некоторых внутренних данных.
источник
Вы можете передать выражение по значению, это естественно. Передача выражения по (временной) ссылке ... странно.
источник
Если вы переходите по ссылке, то вы фактически всегда работаете с глобальными значениями, со всеми проблемами глобальных параметров (а именно с областью действия и непреднамеренными побочными эффектами).
Ссылки, как и глобальные, иногда полезны, но они не должны быть вашим первым выбором.
источник