2011-01-25 3 views
11

스칼라가 ALGOL의 호출 이름을 지원한다는 것을 알고 있으며, 이것이 의미하는 바를 이해하고 있다고 생각하지만 스칼라는 C#, VB.NET 및 C++와 같은 참조 호출을 수행 할 수 있습니까? 나는 자바가 참조에 의한 호출을 할 수 없다는 것을 알고 있지만,이 제한이 전적으로 언어 나 JVM 때문인지 확신 할 수 없다.Scala는 참조로 호출 할 수 있습니까?

엄청난 데이터 구조를 메서드에 전달하려고하지만이 메서드의 복사본을 만들지 않으려는 경우에 유용합니다. 이 경우 call-by-reference가 완벽 해 보입니다.

+1

저는 스칼라에서 값으로 데이터 구조를 전달할 수 있다고 생각하지 않았습니다. – Gabe

+0

@Gabe 여전히 [패스/값 별 호출] (http://en.wikipedia.org/wiki/Evaluation_strategy) (AnyRef 유형에 대한 패스 - 바이 - 오브 - 오브 - 오브젝트 - 레퍼런스 및 파이썬/자바 사람들은이를 위해 "pass-by-reference"용어를 악용하고 싶어합니다. 그러나, pass/by-reference는 함수 *에 변수 *를 설정하면 전달 된 변수의 값을 설정한다는 것을 의미합니다 (VB에서 C++ 또는 ByRef, C#에서 out/ref 등). . 이것은 전달 된 객체와 상태 변이로 * 에뮬레이션 될 수 있지만 동일하지는 않습니다 (C는 포인터에 의해 참조 된 값을 수정하여 에뮬레이트 할 수 있습니다). –

+1

@pst : "방대한 데이터 구조를 메서드로 전달"부분을 참조하고있었습니다. 스칼라는 데이터 구조를 함수로 전달할 때 데이터 구조를 복사하지 못하거나 데이터 구조가 이미 참조로 전달 되었기 때문에 OP의 인용 부호와는 관련이 없습니다. – Gabe

답변

34

Java 및 Scala는 모두 값으로 호출을 독점적으로 사용합니다. 단, 값은 프리미티브 또는 객체에 대한 포인터입니다. 개체에 변경 가능한 필드가 포함 된 경우에는 참조와 참조 사이에 실질적인 차이가 거의 없습니다.

항상 개체에 대한 포인터를 개로 전달하기 때문에 반복적으로 거대한 개체를 복사 할 필요가 없습니다.

부수적으로 스칼라의 이름 호출은 호출 결과를 사용하여 구현되며 값은 표현식의 결과를 반환하는 함수 객체에 대한 포인터입니다.

+0

효과가있는 변경 가능한 입력란에 대해 자세히 설명해 주시겠습니까? – royco

+1

글쎄, 변수'x'를 돌연변이시키고 싶다고합시다. C에서'int * x'로 전달할 수 있습니다. 스칼라에서는 클래스에 'class X (var x : Int)'라는 변수를 넣을 수 있습니다. 이제 그 클래스를 어떤 메서드에 전달하면'x'의 값을 변경할 수 있습니다. –

+11

스칼라가 값으로 호출을 독점적으로 사용한다고해서 언어와 구현이 혼동된다고합니다. 어셈블러에 가면 모든 언어가 값으로 만 호출됩니다. Scala _could_는 참조 나 프리미티브를 전달할 컨테이너 객체를 생성 한 다음 호출이 반환되면 컨테이너에서 다시 읽는 것과 같이 JVM에서 참조별로 호출을 지원할 수 있습니다. –

0

"모든 것이 개체입니다."개체 참조에 액세스 할 수없는 언어의 경우. Java 및 Scala이면 모든 함수 매개 변수는 언어 아래의 추상화 수준에서 값에 의해 전달되는 참조입니다. 그러나 언어 추상화의 의미에 따르면 함수에 참조 된 객체의 사본이 제공되는지 여부에 따라 호출 별 또는 호출 별이 있습니다. 이 경우 call-by-sharing이라는 용어는 추상화의 언어 수준에서 참조 별 호출과 값 별 호출을 모두 포함합니다. 따라서 Java는 언어 의미 (즉, 가상 머신의 경우 C 또는 바이트 코드로 변환되는 방식을 비교하는 것) 아래의 추상화 수준에서 가치에 의한 호출이라고 말하면서 Java 및 스칼라는 "모든 것이 객체 다"추상화의 의미에서 참조로 호출 (내장형 제외)합니다.

자바 및 스칼라에서는 특정 내장 (a/k/프리미티브) 유형이 자동으로 값 (예 : int 또는 Int)으로 전달되고 모든 사용자 정의 유형이 참조로 전달됩니다 (즉, 그들 만의 가치를 전달하십시오).

참고 위키 백과의 Call-by-sharing section을 업데이트하여보다 명확하게했습니다.

아마도 위키 백과에서는 값별 전달과 값 별 호출의 구분에 대해 혼동을 느낍니까? 대입 표현식과 함수 적용에 적용 할 때 값에 의한 전달이 더 일반적인 용어라고 생각했습니다. 나는 Wikipedia에서 그 교정을하려고 노력하는 것을 성가 시게하지 않았다.

개체가 불변 인 경우 호출 기준 및 값 별 호출간에 "모든 것이 개체"인 의미의 수준에는 차이가 없습니다. 따라서 call-by-value 대 call-by-reference의 선언을 허용하는 언어 (예 : 내가 개발중인 스칼라와 같은 언어)는 객체가 수정 될 때까지 값에 의한 복사를 지연시킴으로써 최적화 될 수 있습니다.


분명히 이것을 투표 한 사람들은 "공유 호출"이 무엇인지 이해하지 못합니다.

다음은 내가 평가 전략에 대해 논의한 나의 Copute 언어 (JVM 대상)에 대해 작성한 내용을 추가합니다.


심지어 순결 함으로, 튜링 완전 언어재귀를 허용하는)은 평가 전략을 선택해야하기 때문에 완벽하게 선언적입니다. 평가 전략은 함수와 인수 사이의 상대적 런타임 평가 순서입니다. 함수의 평가 전략은 strict 또는 non-strict 일 수 있으며, 모든 표현식이 함수이므로 eager 또는 lazy와 동일합니다. Eager는 인수 표현식의 함수가 평가되기 전에 평가된다는 것을 의미합니다. 반면에 lazy는 인수 표현식이 함수에서 처음 사용 된 런타임에만 평가된다는 것을 의미합니다. 평가 전략은 성능, 결정 성, 디버깅 및 운영상의 의미 상 트레이드 오프를 결정합니다. 순수한 프로그램의 경우, 순수성으로 인해 평가 순서의 명령형 부작용이 메모리 소비, 실행 시간, 대기 시간 및 비 - 종단 도메인에 비 결정론을 야기하기 때문에 (즉, 범주 적으로 한정되어 있기 때문에) 의미 적 의미 결과를 변경하지 않습니다. .

근본적으로 모든 표현식은 함수가 있습니다. 즉 상수는 입력이없는 순수 함수이고, 단항 연산자는 하나의 입력을 가진 순수 함수이고, 이항 연산자는 두 개의 입력을 갖는 순수한 함수이고, 생성자는 함수이며, 심지어 제어문 (예 : if, for, while)을 함수로 모델링 할 수 있습니다. 이러한 함수를 평가하는 순서는 구문에 의해 정의되지 않습니다 (예 : f (g())는 g의 결과를 열심히 평가할 수 있거나 f를 평가할 수 있고 f의 결과가 f 내에 필요할 때만 l을 천천히 평가할 수 있습니다.

전자 (eager)는 값 별 호출 (CBV)이고 후자 (lazy)는 이름 별 호출 (CBN)입니다. CBV는 Java, Python, Ruby 등과 같은 현대 OOP 언어에서 유행하는 불일치 함수가 암시 적으로 변경 가능한 객체를 참조로 암시 적으로 입력하는 공유 호출 방식을 사용합니다. CBN에는 함수 인수가 한 번만 평가되는 (CBN) 변형이 필요합니다 (함수를 메모하는 것과 같지 않음). Call-by-need는 call-by-name 대신 거의 항상 사용됩니다. 왜냐하면 call-by-name이 기하 급수적으로 빠르기 때문입니다. 일반적으로 CBN의 두 변종은 선언 된 기능 계층 구조와 런타임 평가 순서 사이의 불일치 때문에 순결로만 나타납니다.

언어에는 일반적으로 기본 평가 전략이 있으며 일부는 선택적으로 옵션이 기본값이 아닌 것으로 평가되도록 강제로 구문을 사용합니다. 기본적으로 열망하는 언어는 대개 두 번째 피연산자가 아닌 부울 결합 (a/k/a "및"& &) 및 분리 (a/k/a "또는", |||) 연산자를 지연 평가합니다. 절반의 경우에 필요하다. anything == true와 false & & anything == false.

+0

다음은 참조입니다. http://lambda-the-ultimate.org/node/4180#comment-64168 –

0

다음은 스칼라에서 참조 매개 변수를 에뮬레이트하는 방법입니다.

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) 

글쎄, 파스칼이나 C++ 프로그래머가 익숙한 것은 아닙니다. 하지만 스칼라에서는 거의 없습니다. 이것은 매개 변수로 전송 된 값으로 수행 할 수있는 작업에 유연성을 제공합니다. 예 :

someFunc((x => println(x))) 
관련 문제