Может ли Scala позвонить по ссылке?

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

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

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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


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

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


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

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

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

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

Ответ 3

Вот как эмулировать ссылочные параметры в 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 или С++; но тогда очень мало в Scala. Поверхность заключается в том, что это дает абоненту большую гибкость с тем, что они могут сделать со значением, отправленным параметру. Например.

someFunc( (x => println(x) ) )