Call by Reference, Call by Value에 대한 고찰

Programming/Extractions 2021. 2. 11. 14:06

Call by Reference와 Call by Value는 프로그래밍에서 기본적인 내용이다. Call by Value는 용어가 어렵지만 아주 직관적이다. 어떤 변수에 쓰여진 값이 있다면 그 값을 그대로 가져오라는 뜻이다. 반면에 Call by Reference는 포인터에 대한 개념을 알면 이해하기 쉽다.

어떤 변수에 쓰이는 값은 여러 번 사용하기 위해서는 메모리 어딘가에 저장이 되어야 하는데, 이 때 메모리의 주소를 포인터라고 보면 된다. C/C++로 프로그래밍을 한다면 이걸 상당히 고수준으로 사용해야 하지만, 그러나 대부분의 프로그래밍 언어에서는 직접적으로 포인터를 사용하지 않는다. 포인터가 많아지면 디버깅이 상당히 어려워지기 때문이다. 

그럼에도 불구하고 분명히 포인터와 같은 Call by Reference는 대부분의 프로그래밍 언에에서 이용되고 있다. 대표적으로 List 클래스를 살펴보면, 아래와 같이 좌변의 List A에 특정 List B를 입력한 후 B의 어떤 원소를 삭제한다면 List A에서도 동일한 원소가 삭제된다. 만약 Call by Value였다면 List B와는 별개로 List A의 값이 그대로 보존되었을 것이다. 이러한 예시는 비단 Java 뿐만 아니라 대부분의 프로그래밍 언어에서도 마찬가지다.

List A = []
List B = [ 'xxx', 'yyy', 'zzz' ]
A = B
B.removeElement(0)


A => [ 'yyy', 'zzz' ]
B => [ 'yyy', 'zzz' ]

사실 Call by Reference는 객체지향에서 class의 전형적인 특징이라고 보는 것이 옳다. 객체의 상태나 행동의 변경은 시간이나 장소에 상관없이 연쇄적으로 발생할 수 있는데 이런 무질서를 효과적으로 다루는 데에는 Call by Reference가 훨씬 용이하다. 자유의 여신상이 어떻게 생겼는지 궁금하다면 Call by Reference의 경우 인터넷으로 이미지 검색을 하여 확인하지만, Call by Value는 직접 비행기를 타고 미국에 가서 확인하는 경우이라고 보면 된다. 예시가 조금 부적절해 보일 수 있지만 그만큼 Call by Value가 주류가 되는 프로그래밍이 번거롭고 귀찮다는 것을 비유적으로 표현하기 위해 언급하였다.

물론 Call by Reference가 만능은 아니다. 문서의 원본이 보존되어야 하는 경우가 있듯이 프로그래밍에서도 데이터 원본이 유지되어야 하는 경우가 있다. 또한 때로는 다른 객체에 원본의 데이터를 파라미터로 주어야 하는 경우가 발생하기도 한다. 이럴 때는 선택의 여지없이 객체 복제(object clone)를 해야 한다. 자바에서는 아래처럼 clone 함수를 이용하여 수비게 수행할 수 있지만, 경험상으로 다른 언어에서 객체 복제를 위해서 클래스 내에 별도의 함수를 선언하여 클래스가 가진 모든 변수를 일일이 지정한 적이 꽤 있다.

super.clone()

 

정리하자면 이처럼 프로그래밍에서 값이 다루어지는 방식에 따라 Call by Reference와 Call by Value로 나눌 수 있으며, Call by Reference는 실제 값이 존재하는 메모리의 주소를 참조하여 간접적으로 값을 불러오는 방식이지만, Call by Value는 메모리에 있는 값을 직접적으로 복제하여 사용하는 방식이라 할 수 있다. 이들과 거의 비슷한 의미를 가진 용어로는 Shallow-Copy와 Deep-Copy가 있으며, 각각 Call by Reference와 Call by Value와 맥락을 같이 한다고 볼 수 있다. 경험에 비춰 봤을 때 Call by Reference와 Call by Value는 이론 설명을 위하여 주로 사용되지만, Shallow-Copy와 Deep-Copy는 개발이나 디버깅과 같이 실무적은 측면에서 자주 언급된다.

admin