Closure란 무엇인가?

2026. 5. 6. 01:50·Kotlin

Closure?

사실 Closure를 처음 들었을 때, 도대체 뭘 뜻하는 것인지 감이 잘 오지 않았다. 이러한 일을 겪을 땐 우선 사전적 의미를 먼저 찾아보곤 한다. 

https://dictionary.cambridge.org/dictionary/english/closure

대강 동작이 중지된, 닫힌 상태를 나타내는 것으로 보인다. 그러고 보니, 수학 시간에 Closure라는 의미를 들어봤던 것 같았다. 이에 관련하여 찾아보니, 다행히도 내 기억이 맞았다. 

https://ko.wikipedia.org/wiki/%ED%8F%90%ED%8F%AC_(%EC%88%98%ED%95%99)

수학시간에서의 Closure는 다른 집합에 속하지 않을 가능성이 닫혀있다? 라는 의미로 생각했던 것 같다. 

 

프로그래밍에서는 뭔데?

원래 이정도 찾아봤으면 대충 뭐하는 친구인지 예상이 가기 마련이었는데, 이번엔 감이 잘 안잡혔다.

일단 정의를 찾아봤다

Lexical?, Lexical scope? (나에게 매우)어려운 단어가 나왔지만, 일단 first-class function를 보니, 일급 함수와 관련된 내용인 것 같다. 

Lexical에 대한 힌트도, storing a function together with an enviornment 에서 얻어볼 수 있었다.

 

결론적으로, 요지는 "scope"(범위)다. 즉 어떤 변수의 값을 무엇을 기준으로 결정할 것인가? 에 대한 약속에 대한 내용이다. 

이야기가 조금 산으로 가는 것 같지만, 이런 규칙을 왜 정의해야 했을까?

 

컴퓨터는 바보다...

바로 언어에서 "자유 변수"를 사용하기 위해서이다. 

자유 변수는 현재 블록에서 선언되지 않고 사용되는 변수이다. 

fun outer() {
    val x = 10

    fun foo() {
        println(x) // x는 자유 변수
    }
}

 

foo 함수의 x는 foo 함수 내에서 선언된 것이 아님에도 사용되고 있다. 이렇게 사용하는 것이 너무 당연하게 생각될 수도 있다. 

하지만 전역 변수로 선언해둔 것이 아니라면, 

컴파일 타임에는 어떤 함수의 스택 포인터를 알 수 없기 때문에(런타임에 호출 시 할당되므로) 컴파일 할 때, 컴파일러는 x라는 변수의 주소를 알 방법이 없다. 

 

이 방법에 대한 해결책은 다음이 있을 것이다.

 

1. 쓰지 마셈!! (컴파일 할 때 에러)

   이 경우에는 자유변수를 사용하지 못하므로, 다른 scope에서 어떤 변수를 사용하려면 파라미터로 다 받아야 할 것이다. 

2. 모든 변수를 전역 변수화(컴파일할 때 주소를 전부 결정되도록) 

   큰일날 것 같긴 하다. 우선 당장 생각나는 문제점은 메모리 낭비, 그리고 멀티 스레드 환경에서의 취약성도 있을 것이다. 

 

위 선택지 중에는 딱히 만족스러운 선택지는 없는 것 같다. 이러한 상황에서 lexical, dynamic scope을 이해해보자 

 

lexical scope

우선 lexical scope은 함수가 정의된 위치를 기준으로 자유 변수를 찾는 것이다. 

var x = 10

fun printX() {
    // 컴파일 타임에는 wrapper의 x를 모른다. 
    // 전역 변수 x를 캡쳐해간다.
    println(x) 
}

fun wrapper() {
    var x = 20 
    printX()
}

fun main() {
    wrapper() // println(10)
}

 

printX 함수의 변수 x를 중점으로 코드를 살펴보자, lexical scope을 기준으로 삼는다면

정의된 위치를 기준으로 자유 변수를 찾는 것이므로,  컴파일러는 전역 변수 x를 자유 변수로 고를 것이다.

 

자유 변수로 고른다, 라는 것은 아마 컴파일 시 해당 함수 스택 내부의 멤버로 추가해 줄 것으로 생각된다. 혹은 힙에 이동시킨다거나.. 이에 대한 세부 구현은 잘 모르겠다. 

 

dynamic scope

dynamic scope은 이름에서 예상할 수 있듯이 동적으로, 즉 런타임에 결정한다. 즉 런타임이 함수 호출 스택을 거슬러 올라가며, 자유 변수를 찾는다. 

실제 동작을 생각해보면 다음과 같을 것이다.

    1. 우선 해당 함수 내의 스택에서 못찾음

    2. 이전 스택(해당 함수를 호출한 함수의 스택)으로 이동하여 찾음

    3. 찾을 때까지 반복... 

var x = 10

fun printX() {
    println(x) 
}

fun wrapper() {
    var x = 20 
    printX()
}

fun main() {
    wrapper() 
    // wrapper를 호출한다. 
    // wrapper내에서 printX를 호출한다. 
    // x가 없네? wrapper의 스택으로 이동
    // wrapper에서 x를 찾음!
    // println(20)
}

 

둘 중에 뭘 사용하는게 좋을까?

지금까지 어떤 문제가 있었고 이에 대한 해결 방법들을 살펴봤다(안쓰기, 전역변수화 하기, lexical scope, dynamic scope)

 

그런데, 최근 언어들은 전부 lexical scope 방식을 사용하고 있다. 왜 dynamic scope 방식은 사용하지 않을까?

이러저러한 이유를 찾아봤지만, 내 생각에는 다음과 같은 이유가 가장 큰 것 같다. 

 

dynamic scope 방식을 사용했을 때는 함수의 동작을 예측하기 힘들다. 

원래 함수라는 것이 다양한 output을 내놓을 수 있다지만, dynamic scope을 사용하게 되면,
함수의 주변 context에 따라 선정될 수 있는 자유변수가 다를 수 있기 때문에, 호출한 부분의 주변 context에 직접적으로 영향을 받게된다. 

 

이러한 언어를 사용해본 것은 아니기에 단언할 수는 없지만, 자유 변수를 못 찾을 가능성도 있으므로, 런타임에 프로그램이 터질 수도 있을 것이다. 

 

결국 그래서 Closure는 뭔데?

조금 먼 길을 온 감이 있어 원래 탐구하고자 한 Closure에 대한 기억이 희미할 것 같다. 하지만, 이제 다시 Closure의 정의를 보면 다르게 보일 것이다. 

 

결국 Closure는  lexical scope 규칙에 의거하여 자유변수를 들고 있는 어떤 함수의 상태, 캡쳐본이다. 다른 말로 해보면,

lexical scope는 자유변수를 정하기 위한 규칙이고, Closure는 이를 이용한 결과물이라고 할 수 있을 것 같다. 

 

'Kotlin' 카테고리의 다른 글

[우테코 8기 모바일 안드로이드] 레벨 0 4주차 회고  (0) 2026.02.23
Kotlin in action 2/e: 코루틴(1) 코루틴이란 무엇인가?  (0) 2026.02.23
Kotlin in action 2/e: DSL 만들기(1) DSL이란 무엇인가?  (0) 2026.02.23
Kotlin in action 2/e: 어노테이션과 리플렉션(1) 코틀린의 어노테이션  (0) 2026.02.20
Kotlin in action 2/e: 고차함수: 람다를 파라미터와 반환값으로 사용(2) 인라인 함수, 코틀린 표준 라이브러리의 인라이닝  (0) 2026.02.19
'Kotlin' 카테고리의 다른 글
  • [우테코 8기 모바일 안드로이드] 레벨 0 4주차 회고
  • Kotlin in action 2/e: 코루틴(1) 코루틴이란 무엇인가?
  • Kotlin in action 2/e: DSL 만들기(1) DSL이란 무엇인가?
  • Kotlin in action 2/e: 어노테이션과 리플렉션(1) 코틀린의 어노테이션
Kirbyyy
Kirbyyy
개인적인 일상과 회고를 기록하는 블로그입니다.
  • Kirbyyy
    커브볼의 생존일지
    Kirbyyy
  • 전체
    오늘
    어제
    • 분류 전체보기 (53)
      • 우아한테크코스 (8)
      • 프로덕트 빌드 (0)
      • Problem Solving (20)
      • C++ (0)
      • Kotlin (19)
      • Java (3)
      • CS (2)
        • AI (2)
      • 취미생활 (0)
        • 서평 (0)
        • 프라모델 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백준 1356
    백준 31575
    BFS
    백준 알고리즘
    다이나믹 프로그래밍
    백준 16174
    그리디 알고리즘
    C++
    우테코 8기
    Problem Solving
    백준
    백준 11123
    너비 우선 탐색
    백준 33272
    백준 16173
    백준 파도반 수열
    ProblemSolving
    분할 정복
    백준 연속 합
    백준 RGB 거리
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Kirbyyy
Closure란 무엇인가?
상단으로

티스토리툴바