ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 함수 2
    코-드 스피츠/함수와 oop 2019. 1. 6. 23:25

    이 강의의 발췌록 입니다.

    https://www.youtube.com/watch?v=h80tLv0fn88&index=2&list=PLBNdLLaRx_rKOFzA3txlG5rf9ZaVUuvmv


    SPREAD REF

    SUB ROUTINE CHAIN

    TAIL RECURSION

    TAIL RECURSION TO LOOP


    -----------------------------------------------------------------


    CLOSURE

    NESTED CLOSURE

    SHADOWING

    CO ROUTINE



    1. SPREAD REF


    참조값은 잠깐 오염대로 끝나는 게 아니라 그 오염이 계속 전파된다. 



    B는 참조값.


    새로만든 로컬변수 LA는 routine A의 인자 B를 물고 있습니다.


    새로만들었지만 LA가 B를 물고 있기 때문에,


    그렇게 되면, main flow의 변수 a와 b는 상호간의 참조관계가 생기게 됩니다.


    참조를 보냈는데 참조를 계속 유통시키면 


    상호참조관계로 계속 오염이 번집니다.


    겁니서 a를 지울 수 없거나 b를 못건드리게 됩니다.


    '함수 1'(https://evankitchen.tistory.com/8)의 [55:36]에서 말한 


    '로컬변수로 새 참조를 만들어서 return하기'를 충족했음에도 불구하고 


    인자로 넘어간 참조값 b를 물고 있기 때문에 문제가 해결되지 않습니다.


    그럼 계속 연쇄참조를 물게 됩니다. 


    오염이 어디서 일어났는지 디버깅시 파악이 안됩니다. 



    [3:28]

    문제가 어디서 일어나냐면 A가 B와 관련된 행위를 밖에서 하면 문제가 생깁니다. 


    routine 함수 내부에서는 LA가 나중에 어떤 일을 발생시킬지 알 수 없습니다. 


    참조를 소유한 참조객체를 '새로' 만들어'도' 참조의 여파(또는 오염)는 끝나지 않습니다. 


    루틴 바깥쪽이 통제 밖이기 때문에. 


    따라서 복사본을 return하세요.


    이 모든 문제의 근원은 B를 그냥 쓰는 것입니다. 


    복사본이라는 의미에서 보면 새 객체를 만들지 않은 점에서는 인자로 보내도 여전히 새 객체가 아닙니다. 


    LA에 B를 넘길 때 복사본 B를 넘겼어야만 합니다. 


    인자로 넘어간 참조값도 모두 복사해서 넘겨야 합니다.




    정리[4:50]

    루틴과 서브루틴이 대화할 때 리턴과 인자를 통해서 대화를 합니다.


    이때 되도록 참조값을 쓰지 않고, 


    만약 쓴다면 내부에서 새로운 복사본을 만들어서 리턴하거나 지역변수로 사용 합니다.


    복사본을 사용하는 대상은 만들어진 값(인자와 지역변수)만 포함되지 않고 


    만들어진 값에게 인자로 넘겨진 값 역시 적용됩니다.(LA(B)같은놈)


    다른 객체의 인자로 넘어간 것 역시 체크해야 한다는 말씀.



    2. SUB ROUTINE CHAIN



    R6에서 이친구들을 리턴하기 전까지의 서브루틴을 모두 콜스택 메모리에 저장하고 있습니다.


    리턴이 시작되면 하나씩 까면서 마지막 R1이 리턴됩니다. 



    정확하게 메모리에 keep되는 콜스택들은 각 서브루틴의 '인자값과 로컬변수' 입니다.


    [7:00]

    호출되는 순간 함수는 하나 분량의 미니 메모리를 갖게 됩니다.

    이게 자스 엔진에서 부르는 실행 컨텍스트, execution context입니다.

    함수를 호출할 때 부르는 메모리이며 리턴되기 전까지 유지합니다. 


    [8:10]

    루틴에서 리턴 이후는 없습니다.다시말해 return R2()를 하면 그 이후에는 R1의 메모리가 필요 없습니다. 그렇게 되면 R1 함수의 return R2()에서 메모리를 유지해야만 할까요? 유지안해도 되지 않을까요? 


    [9:35]

    R1에서 더이상 메모리를 유지할 필요가 없다면 R1의 리턴포인트에서 R2로 이동할 때 다시 돌아올 리턴포인트를 R1의 리턴이 아닌 Main flow의 리턴포인트(그림 상에서 A = R1() 쪽)로 보내면 어떨까요? 

    (리턴포인트는 언어수준에서 결정됩니다)



    [10:40]

    더이상 콜스택이 없게 됩니다. 함수를 아무리 콜해도 유지하는 메모리가 없게 됩니다.  

    이거슨 언어수준에서 도와줘야합니다.


    [11:45]

    그럼 꼬리물기 최적화의 조건은? 각 서브루틴의 리턴단에서 위의 메모리(지역변수, 인자)를 해지할 수 있게 함수를 짜야 합니다. 

    이방식으로 호출을 바꾸면 호출하는 엔진이 굉장히 효율적으로 메모리를 쌓아두지않고 함수를 처리하고 메모리를 해지하고(반복)하는 제어문의 루프처럼 움직입니다.

    제어문 루프는 포문 안의 것들을 메모리에 유지하지 않습니다. 인덱스 변수 빼고 다 해지합니다. 이것을 제어문의 스택 클리어 기능이라고 합니다. 제어문은 연속된 호출에 대하여 제어문을 통해서 스택을 클리어하는 기능이 있습니다. 따라서 제어문에선 반드시 while, for 같은 문장을 써야지만 루프에 대한 스택을 클리어 시킬 수 있습니다. 따라서 제어문의 루프문들은 스택클리어 기능이 있습니다. 안해주는 구식 언어도 있습니다. 

    여러분이 for문을 goto문의 우아한 표현이라고 생각하시면 큰 오산이라능. for문은 처음에 루프돌리는 블럭에 대해서 스택영역을 지정해서 실행한 다음에 다음번 루프로 점프할 때 앞에 있는 스택메모리를 해지하는 기능이 있습니다. 우리가 쓰는 abc언어들의 제어문들은 루프 블럭에 대한 스택 클리어 기능이 있습니다. 그런데 언어가 함수 수준에서 그걸 지원하면 제어문의 도움을 받지않고 똑같은 걸 구현할 수 있습니다. 다시 말해 꼬리물기 최적화를 하면 루프문의 지원없이 고성능의 루프문을 구현 가능합니다. 


    [15:10]에서 계속










    '코-드 스피츠 > 함수와 oop' 카테고리의 다른 글

    함수 4  (0) 2019.02.11
    함수 1  (0) 2019.01.03
Designed by Tistory.