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

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

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

3 ответа

Решение

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

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

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

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

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

Обратите внимание, что я обновил раздел Википедии " Call-by-share", чтобы сделать это более понятным.

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

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


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

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


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

По сути, все выражения являются (композицией) функций, то есть константы являются чистыми функциями без входов, унарные операторы являются чистыми функциями с одним входом, бинарные операторы являются чистыми функциями с двумя входами, конструкторы являются функциями и даже управляющими операторами (например, если, для, while) можно смоделировать с помощью функций. Порядок, в котором мы оцениваем эти функции, не определяется синтаксисом, например, 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 "или", ||), потому что второй операнд не нужен в половине случаев, т.е. верно || все == правда и ложь && что угодно == ложь.

Вот как эмулировать эталонные параметры в 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) ) )

Я читал по этой теме и видел эти вопросы и ответы. Я стал с этим примером, который действительно работает, если вы скопируете и вставите его в текстовый файл и сохраните его как *.bat, например testref.bat:)


::#! 
@echo off 
call scala -savecompiled %0 %* 
goto :eof 
::!# 

  class X( var x: Array[String] )
  val mybb = new X(Array("ss", "dd"))
  println("Printing x array:")
  mybb.x.foreach( e => println(e))

  mybb.x = mybb.x :+ "Carlos"

  println("Printing x array, carlos added:")
  mybb.x.foreach( e => println(e))

  updateMyVar(mybb)

  println("Printing x array, kassab added:")
  mybb.x.foreach( e => println(e))


  def updateMyVar( mycc: X ): Unit =
  {
    mycc.x = mycc.x :+ "Kassab"
  }

Я просто хотел бы подтвердить, действительно ли это способ вызова переменных по ссылке?

Другие вопросы по тегам