call by value vs call by reference (feat. call by sharing)

Aaron·2020년 11월 9일
1

Javascript

목록 보기
1/1
post-thumbnail

평가 전략 (evaluation strategy)


정의

프로그래밍 언어에서 함수 호출의 아규먼트(argument)의 순서를 언제 결정하고 함수에 어떤 종류의 값을 통과시킬지 결정하는 것

함수 실행 시 인자로 무엇을 던지느냐에 따라 함수가 어떻게 실행될지 결정하는 것

종류

  • 엄격한 평가

    • 인자 우선 계산(Applicative order)
    • 값에 의한 호출(Call by value)
    • 참조에 의한 호출(Call by reference)
    • 공유에 의한 호출(Call by sharing)
    • copy-restore에 의한 호출(Call by copy-restore)
  • 엄격하지 않은 평가

    • 일반 순서(Normal order)
    • 이름에 의한 호출(Call by name)
    • 요구에 의한 호출(Call by need)
    • 매크로 확장에 의한 호출(Call by macro expansion)

call by value


정의

Call by value (also known as pass by value) is the most common evaluation strategy, used in languages as different as C and Scheme. In call by value, the argument expression is evaluated, and the resulting value is bound to the corresponding variable in the function (frequently by copying the value into a new memory region). If the function or procedure is able to assign values to its parameters, only its local variable is assigned—that is, anything passed into a function call is unchanged in the caller's scope when the function returns.

직역하자면 함수를 값으로 호출한다. 무슨 값이냐? 복사된 값이다.
즉, caller에서 받은 argument를 callee의 parameter로 전달할 때, 값을 복사해서 넘겨준다. 아래 예시를 보자.

예시

모든 예시의 변수 선언은 브라우저 콘솔 창에서의 테스트 편의성을 위해 var 키워드로 하겠습니다.

  • argument가 원시값인 경우
var value = 2;

var callee = (copiedValue) => {  // 이 줄에서 copiedValue = 2와 동일한 동작이 수행됨
  copiedValue = copiedValue + 1;
};

callee(value); // caller
console.log(value); // 2

caller에서 argument를 받아 값을 복사한 뒤 callee의 parameter로 넘겨주는 과정은 할당 연산자를 이용하는 것과 같다. (e.g copiedValue = 2)
때문에 callee의 로직에서 1을 더해도 콘솔에는 기존 2가 찍히는 것을 볼 수 있다.
따라서 javascript 함수는 argument가 원시값일 경우 call by value 방식으로 평가된다고 볼 수 있다.

  • argument가 원시값이 아닌 경우
var obj = { changed: false };

var callee = (memoryAddressOfOriginObject) => {
  memoryAddressOfOriginObject.changed = true;
};

callee(obj); // caller
console.log(obj); // { changed: true }

javascript의 평가 전략이 call by value라면 콘솔의 결과가 { changed: false } 여야 한다. 하지만 콘솔 결과는 { changed: true } 이다.
copiedValue에 복사된 값 대신 다른 무언가가 전달되고 있다는 의미다.
이는 argument가 원시값이 아니라면 javascript의 평가 전략은 call by value가 아니라는 것을 의미한다.
참고로 copiedValue에 전달되는 값은 value 변수가 가리키는 { changed: false } 객체의 메모리 주소다.

메모리 주소, 원시값에 대해 궁금하다면 이 포스팅을 참고하자

call by reference


정의

Call by reference (or pass by reference) is an evaluation strategy where a function receives an implicit reference to a variable used as argument, rather than a copy of its value.

직역하자면 함수를 참조로 호출한다. 참조가 뭐냐? 메모리 주소다.
call by value는 caller의 argument 값을 복사해 callee로 넘겨주는 반면,
call by reference는 caller의 argument 원본 객체의 메모리 주소를 callee로 넘겨준다. 아래 예시를 보자.

예시

  • 동적 프로퍼티 할당
var obj = { changed: false };

var callee = (memoryAddressOfOriginObject) => {
  memoryAddressOfOriginObject.changed = true;
};

callee(obj); // caller
console.log(obj); // { changed: true }

callee 함수의 로직에서 실제 obj 객체에 접근해서 changed 프로퍼티가 true로 바뀐 것을 볼 수 있다.
여기서 쉽게 할 수 있는 오해가 argument를 parameter로 전달할 때 원본 객체가 전달된다고 착각하는 것이다.
여기서 javascript는 callee의 parameter에 argument의 원본 객체가 아닌,
참조(메모리 주소)만 전달할 뿐이다.
좀 더 자세한 내용은 이 링크의 첫 번째 예시 아래에 적혀있으니 헷갈린다면 읽어보자.
이제 아래 예시에서 더 확실히 해보자.

  • 재할당
var obj = { changed: false };

var callee = (memoryAddressOfOriginObject) => {
  memoryAddressOfOriginObject = { changed: true };
};

callee(obj); // caller
console.log(obj); // { changed: false }

c++과 같이 call by reference로 동작하는 언어라면 위 콘솔의 결과가 { changed: true }가 되어야 한다. 하지만, javascript는 { changed: false }라는 결과를 뱉는다.
대체 javascript 함수는 어떤 방식으로 평가되는 걸까?

참고로 위 로직에서는 아래와 같은 일이 일어난다.

  1. 할당 연산자(=)의 우변 { changed: true }가 새로운 메모리 주소에 생성된다.
  2. 할당 연산자(=)의 좌변 accessToActualObj는 더 이상 obj로의 access를 의미하지 않는다. 대신 위에 새로 메모리에 올라간 { changed: true }의 메모리 주소를 가리키게 된다.
  3. 함수 호출이 완료되면 스코프를 벗어나게 되므로(닿을 수 없게 되므로) 가비지 콜렉션 처리가 되어 메모리가 해제된다.

call by sharing


정의

Call by sharing (also known as "call by object" or "call by object-sharing") is an evaluation strategy first noted by Barbara Liskov in 1974 for the CLU language. It is used by languages such as Python, Java (for object references), Ruby, JavaScript, Scheme, OCaml, AppleScript, and many others. However, the term "call by sharing" is not in common use; the terminology is inconsistent across different sources. For example, in the Java community, they say that Java is call by value. Call by sharing implies that values in the language are based on objects rather than primitive types, i.e., that all values are "boxed". Because they are boxed they can be said to pass by copy of reference (where primitives are boxed before passing and unboxed at called function).

The semantics of call by sharing differ from call by reference: "In particular it is not call by value because mutations of arguments performed by the called routine will be visible to the caller. And it is not call by reference because access is not given to the variables of the caller, but merely to certain objects". So, for example, if a variable was passed, it is not possible to simulate an assignment on that variable in the callee's scope. However, since the function has access to the same object as the caller (no copy is made), mutations to those objects, if the objects are mutable, within the function are visible to the caller, which may appear to differ from call by value semantics. Mutations of a mutable object within the function are visible to the caller because the object is not copied or cloned—it is shared.

위에서 설명했던 모든 특징을 종합하여 call by sharing이라 한다.
한 마디로 call by value도 아니고 call by reference도 아닌 것이다.
sharing이라 이름 지은 이유가 원본 객체로의 접근을 공유한다는 특징에서 따온 것이 아닐까 조심스럽게 생각해본다.
python, java, ruby, javascript 등의 언어에서 이러한 평가 전략을 사용한다.
특징을 정리하면 아래와 같다.

  1. argument로 전달되는 변수가 원시값일 경우 call by value처럼 평가되고, 아닐 경우는 parameter에 참조(메모리 주소)만 전달된다.
  2. callee의 parameter에는 caller에서 전달한 참조(메모리 주소)만 전달되므로 -> callee에서 동적 프로퍼티 할당을 시도하면 실제 객체의 프로퍼티 값은 바뀌지만 -> 재할당을 시도하면 원본 객체가 재할당되는 call by reference와는 다르게
    우변의 값이 새로운 메모리 주소에 올라가고 좌변의 지역변수는 그 값을 가리키게 된다.

많은 조사를 하였으나 오개념이 있을 수 있습니다. 틀린 부분이 있다면 배울 수 있도록 알려주시면 정말 감사하겠습니다. 읽어주셔서 감사합니다!

참조

profile
Maker를 지향하는 웹 개발자입니다.

1개의 댓글

comment-user-thumbnail
2021년 12월 22일

안녕하세요 자바스크립트 공부한지 얼마 안되서 이해가잘 안되는 부분이 있는데 혹시 동적 프로퍼티 라는게 어떤건지 알수 있을까요??

답글 달기