Может ли Scala звонить по ссылке? - PullRequest
18 голосов
/ 25 января 2011

Я знаю, что Scala поддерживает вызов по имени из ALGOL, и я думаю, что понимаю, что это значит, но может ли Scala выполнять вызов по ссылке, как C #, VB.NET и C ++? Я знаю, что Java не может выполнять вызов по ссылке, но я не уверен, связано ли это ограничение исключительно с языком или также с JVM.

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

Ответы [ 3 ]

42 голосов
/ 25 января 2011

Java и Scala используют исключительно вызов по значению, за исключением того, что значение является либо примитивом, либо указателем на объект. Если ваш объект содержит изменяемые поля, то между этим и вызовом по ссылке очень мало существенных различий.

Поскольку вы всегда передаете указатели на объекты , а не на сами объекты, у вас нет проблемы повторного копирования гигантского объекта.

Между прочим, вызов Scala по имени реализован с использованием вызова по значению, причем значением является (указатель на) функциональный объект, который возвращает результат выражения.

0 голосов
/ 28 марта 2015

Вот как эмулировать эталонные параметры в Scala.

def someFunc( var_par_x : Function[Int,Unit] ) {
    var_par_x( 42 ) // set the reference parameter to 42
}

var y = 0 
someFunc( (x => y=x) )
println(y)

Ну, ладно, не совсем то, к чему привыкли программисты на Pascal или C ++; но тогда очень мало в скале есть. Положительным моментом является то, что это дает вызывающей стороне больше гибкости с тем, что они могут делать со значением, отправленным параметру. Э.Г.

someFunc( (x => println(x) ) )
0 голосов
/ 16 февраля 2011

Для языка, где «все является объектом» и ссылка на объект недоступна, например, Java и Scala, то каждый параметр функции является ссылкой, передаваемой по значению на некотором уровне абстракции ниже языка. Однако с точки зрения семантики языковой абстракции существует либо вызов по ссылке, либо вызов по значению, в зависимости от того, предоставляется ли функции копия ссылочного объекта. В этом случае термин «вызов по совместному использованию» охватывает как вызов по ссылке, так и вызов по значению на уровне абстракции языка. Таким образом, правильно сказать, что Java является вызовом по значению на уровне абстракции ниже семантики языка (т. Е. Сравнивать с тем, как она будет гипотетически переводиться в C или в байт-код для виртуальной машины), и в то же время говорить, что Java и Scala - это (за исключением встроенных типов) вызов по ссылке в семантике своей абстракции «все является объектом».

В Java и Scala некоторые встроенные типы (a / k / a примитив) автоматически передаются по значению (например, int или Int), и каждый определенный пользователем тип передается по ссылке (т.е. их нужно вручную копировать). передать только их значение).

Примечание. Я обновил раздел Википедии , чтобы сделать это более понятным.

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

Нет разницы на уровне семантики, где "все является объектом" между вызовом по ссылке и вызовом по значению, когда объект неизменен. Таким образом, язык, который позволяет объявлять вызов по значению по сравнению с вызовом по ссылке (такой как Scala-подобный язык, который я разрабатываю), можно оптимизировать, задерживая копирование по значению до тех пор, пока объект не будет изменен.


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

Ниже я добавлю описание, которое я написал для моего языка Copute (который предназначен для JVM), где я обсуждаю стратегию оценки.


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

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

Первый (нетерпеливый) - это вызов по значению (CBV), а второй (ленивый) - это вызов по имени (CBN).CBV имеет вариант call-by-share, распространенный в современных языках ООП, таких как Java, Python, Ruby и т. Д., Где нечистые функции неявно вводят некоторые изменяемые объекты посредством ссылки.CBN имеет вариант вызова по требованию (также CBN), где аргументы функции оцениваются только один раз (что не совпадает с функциями запоминания).Call-by-потребность почти всегда используется вместо call-by-name, потому что это экспоненциально быстрее.Обычно оба варианта CBN появляются только с чистотой из-за диссонанса между объявленной иерархией функций и порядком оценки времени выполнения.

Языки обычно имеют стратегию оценки по умолчанию, а некоторые имеют синтаксис для принудительного принудительного принудительного применения.функция, которая будет оценена не по умолчанию.Языки, которые стремятся по умолчанию, обычно лениво оценивают операторы логического конъюнкции (a / k / a "и", &&) и дизъюнкции (a / k / a "или", ||), поскольку второй операнд не нуженв половине случаев, т.е. верно ||все == правда и ложь && что угодно == ложь.

...