본문 바로가기

공부생각/전산잡지식

Parameter passing과 Lazy evaluation



모든 프로그래밍 언어에는 그 각자의 parameter passing 방법과 lazy evaluation방법이 있는데, 코딩을 할때에는 그 각각을 그냥 생각없이 쓰면 아무 문제 없다만,
모든 PL(Programming Language)의 문법에는 뜻이 있으므로,
여기서 한번 이 내용들을 정리하고 뜻을 생각 해 보고자 써본다.

프로그래밍 언어를 공부하는데 도움이 될 것이다.

Parameter passing과 Lazy evaluation, eager evaluation과의 관계는 땔래야 땔 수 없으므로 같이 설명하도록 하겠다.


Parameter Passing(매개변수전달) 방법은 어떤 함수에서 Parameter를 어떻게 전달할 것인가를 다룬다. 예를 들어
int function(int a, int b){
     if(a==1){
           return a;
     }else{
            return a+b;
     }
}

라고 했을 때, 우리가

function(0+1, 100/0);

이라고 어디에서 호출한다면,두 파라매터
(0+1)과 (100/0)이
function이라는 함수안으로 어떻게 들어갈까를 정하는 정책이다.

Parameter passing에는 여러가지가 있는데 몇 가지만 이야기해 보도록 하겠다.

1) Pass by value

     말그대로 값을 pass하는 방법이다. 이것의 경우 위에 예제에서 만약

function(0+1, 100/0);

이렇게 호출한다면 각 파라메터에 있는 연산을 모두 끝낸 다음에 그 값이 함수로 실행되어진다. 따라서

function(1,?);

이것 처럼 안에 있는 계산을 모두 하게된다. 일단 100/0 은 0 으로 나누는, 프로그래밍 언어에서는 커버하지 못하는 오류를 냈으므로 일단 ? 처리해놓았다.(계산되지 못하고 오류를 발생시킨다는 말이다) 하지만 여기서 문제가 무어냐 하면, 모든 연산들을 계산해서 값을 넘기기 때문에, 그 계산하는 과정에서 에러가 발생하면 그냥 바로 error를 발생시키고 (위의 경우에서는 0으로 나누었기때문에), 프로그램은 종료되게 된다. 하지만 위의 예에서 본다면 파라메타 a의 값이 1이기 때문에 함수안에서는 b가 전혀 쓰이지 않으므로 종료될 이유가 없다: <예제1, 2째줄> if(a==1) 을 만족하기 때문에 else문으로 들어갈 여지가 없음.

그렇다면 이 함수는 제 역할을 할 수 있는 순간이었는데, 쓰이지도 않는 b값 때문에 error를 발생시키고 프로그램을 종료하게 되었다. 조금 비 효율적인 부분이다.

언어가 Pass by value 정책을 따르게 되면 Eager evaluation이라고 하는데, 연산을 할수잇을때 다 해버린다는 것이다. 이렇게 되면 사용자로 하여금 사용하는데 더 많은 제약을 주어, 조금 까다로운 언어가 되 버린다. 비록 그 값이 사용되지 않더라도 Parameter의 일부분이된다면 우리는 적을 수도 없게 되버리므로 안정성을 조금 높일지는 몰라도 비효율 적이다.

※Pass by value 는 때때로 pass by reference 와 비교하면서 사용되기도 한다.
이때는
Pass by value는 값을 넘기는 형태이고,
pass by reference는 주소값을 넘기는 형태이다.

두가지의 차이점은 뭐냐면, pass by value는 파라메타의 값을 임시 메모리에 저장시키고 그놈을 가지고 장난치는데 pass by reference는 그 값을 가지고 직접 연산을 한다. Parameter가 그 함수안에서 쓰이고 변화는 하는데 원래 값에 영향을 미치고 싶지 않다면 pass by value로 해야하고, 원래 값도 같이 변하도록 하고 싶다면 pass by reference 를 사용해 주는 것이 옳다.



2) Pass by name

이것도 역시 말그대로 "이름"을 그대로 넘겨주는 방식이다. 이게 무슨 말이냐 하면, 위에서 주어진 예에서

function(0+1, 100/0);

이라고 호출을 한다면 함수는 마치

     if(0+1==1){
return 0+1;
     }else{
            return ((0+1)+(100/0));
     }


이런식으로 실행되는 것과 같다.
그 각각에 주어진 파라메터가 치환되면서 정말 이름그대로 들어가 버리는 것이다. 그럼 위의 바뀐함수를 실행해보면 100/0은 전혀 문제가 되지 않는다. 왜냐하면 이미 두번째줄에 if문 0+1==1 에서 이것이 true값을 리턴하기때문에 else로 들어갈 여지도 주지 않는다. 그래서 이런 Parameter passing방법을 채택하게 되면 비록 100/0 과 같은 잘못된 값을 사용했더라도 그 값이 실질적으로 사용되지 않으면 계산하지조차 않는 효과를 나타내므로, 좀더 함수를 넓은 범위에서 적은 오류 확률로 사용할 수 있게 된다.
하지만 단점은 저런식으로 이름 그대로를 넘기게 된다면 같은 연산을 수천번 하게 된다. 그래서 전체적으로 함수가 비 효율적으로 바뀌는 경향이 있다. 하지만 몇몇 언어에서는 이 방법을 조금 진화시켜서 Pass by need의 방법으로 사용하기도 한다. (Pass by need는 아래에서 설명되어 질 것임)



3) Pass by need

필요에 의해서 파라매타가 전달된다. 이것이 무슨 말일까? 풀어서 말하면 "그 파라매터가 직접 쓰일때 evaluation(연산을 계산)하고, 그 다음 부터는 그 값을 직접 이용한다." 는 것이다. 그래서 pass by name에서 나왔던 단점, 효율성을 떨어뜨리는 문제에 대해서 이 방법으로 극복한 것이다. 이렇게 되면

function(0+1,100/0);

이라고 실행되었을때, 함수의 정의에서 a의 값이 필요할때 (예제에서는 두번째줄 "if(a==1){"에서 a의 정확한 값이 필요) 0+1을 계산하고, 그 계산한 후에는 a가 실행될때 그 값을 그대로 사용하는 방식이다. 그럼 a가 그 함수의 정의안에 수천개가 나온다 하더라도, 한번만 계산되고 나머지는 그 값을 이용하는 꼴이 된다. Pass by name보다는 효율적이고 Pass by value보다는 조금 함수가 관대한(불필요한 오류를 잡아내지않는) 정책이 된다.





생각나는대로 더 추가하겠다.