블로그에 어떤 글을 써야할지에 대해 좋은 조언을 들은 적이 있습니다. 내가 1년 전에 읽을 수 있었으면 좋았을 글을 쓰라는 것이었죠. 이 글은 그런 글입니다. 초심자가 타입 시스템을 잘못 이해하는 경우가 많은데 그 중 몇 가지를 설명하고자 합니다.

타입은 왜 필요한가?

프로그래밍 언어를 처음 접할 때, 보통 최초로 마주치는 것은 그 언어에서 사용하는 타입입니다. 정수형, 실수형, 문자열 등의 타입은 거의 대부분의 언어에서 사용됩니다. 하지만 타입은 왜 필요할까요?

컴퓨터 상에 있는 모든 것은 결국 비트로 처리된다는 것을 상기할 필요가 있습니다. 예를 들어 어떤 파일 1mb는 8388608(2 ^ 23)개의 0 또는 1로 표현됩니다. 이렇게 많은 비트를 사람이 보고 이해한다는 것은 거의 불가능합니다. 하지만 아무 단서가 없을 경우 이를 효율적으로 이해하는 것은 컴퓨터에게도 쉽지 않은 일입니다.

타입 시스템은 비트 덩어리를 어떻게 읽고 쓸 지에 대한 규칙을 정해주며, 엄청나게 많은 비트 사이에서 의미 있는 패턴을 쉽게 인식해낼 수 있는 방법을 제공합니다. 그리고 이렇게 일정 규칙을 따르는 비트 덩어리를 타입이라고 한다고 보면 됩니다.

이해를 위해 레고에 한 번 비유해봅시다. 레고 블럭은 2 x 4, 1 x 4, 2 x 2 등의 일정한 형태와 규칙을 따라 만들어집니다. 이게 레고 블럭의 타입입니다. 반면 그 가장 밑바탕이 되는 1 x 1 블럭만 주어지는 상황을 상상해 보세요. 그 블럭만 가지고도 여전히 복잡한 구조물을 만들 수 있겠지만, 더 크고 규격화된 블럭을 사용해서 만드는 것보다 물리적으로나 정신적으로나 더 품이 많이 들 것입니다.

타입 시스템을 사용하는데는 대가가 있습니다. 사람과 컴퓨터 둘 다 현재 사용하고 있는 특정한 타입 시스템 특유의 규칙을 알고 배워야 합니다. 또한 그 규칙을 따라야 하며, 그렇지 않으면 프로그램이 작동하지 않습니다. 하지만 타입 시스템을 사용할 때의 이득이 비용보다 크기 때문에 모든 프로그래밍 언어에서 타입 시스템이 쓰이고 있습니다.

이제 타입 시스템에 대해 흔히 하는 오해를 몇 가지 살펴봅시다.

강타입, 약타입은 잊어라

타입 시스템을 분류할 때 가장 자주 쓰이는 분류로 강타입, 약타입이 있습니다. 문제는 강타입 약타입에 대한 공식 정의가 없기 때문에 각자 머리속에 서로 다른 방식으로 이를 정의하고 있다는 점입니다. 토론을 해도 토론의 바탕이 될 공통적인 기반이 없기 때문에 결국 모든 토론이 무의미한 감정적 싸움으로 전락해버리고 맙니다.

강타입 약타입에 대한 이야기는 그냥 무시하시면 됩니다. 어떤 타입 시스템이 강타입이라고 누가 말한다면 이렇게 이해하면 됩니다. “내가 좋아하고 안심하며 쓸 수 있는 타입 시스템이다.” 반대로 약타입의 경우는 이렇게 이해하면 됩니다. “내가 쓸 때 걱정되고 불안하게 만드는 타입 시스템이다.”

이분법적인 사고는 그만

타입 시스템은 보통 상호대비적인 방식으로 논의됩니다. 예를 들어 잘 알려진 구분방식으로 정적 타입과 동적 타입 시스템이 있습니다. 하지만 이런 방식으로 타입 시스템에 대해서 이야기하면 타입 시스템이 엄격하게 두 부류로 나뉜다고 오해하기 쉽상입니다.

실제로는 정적 타입 시스템과 동적 타입 시스템은 상호배타적이지 않습니다. 두 시스템은 같은 문제에 대한 두 가지의 다른 접근법이며, 각자 특유의 장단점이 있습니다. 그리고 모든 프로그래밍 언어는 두 가지 접근법의 요소를 모두 사용합니다.

이분법적으로 생각하기보다는 정적 타입 시스템을 동적 접근법보다는 정적 접근법을 주로 사용하는 시스템이라고 생각하는 편이 낫습니다. 동적 타입 시스템은 그 반대고요.

이는 동적 정적 타입 시스템 구분에만 국한되는 것이 아닙니다. 그보다 세세한 타입 시스템 구분법도 마찬가지로 상호배타적이지 않거나, 엄격한 이분법보다는 스펙트럼 상에 위치했다는 느낌으로 이해하는 것이 낫습니다.

타입 선언은 정적 타입 시스템에 반드시 필요한 것은 아니다

저처럼 C와 Java를 통해 정적 타입 시스템을 배웠을 경우 이런 오해를 하고 있을 수도 있습니다. Java에서는 모든 변수의 타입을 명시적으로 선언하도록 하는데, 이를 명시적 타입 선언이라고 부릅니다. 하지만 모든 정적 타입 시스템이 명시적 타입 선언을 필요로 하는 것은 아닙니다.

타입 추정 기능이 있는 정적 타입 시스템에서는 컴파일러가 소스 코드를 분석해서 자동으로 각 변수의 타입을 추정해냅니다. Swift, Haskell, Go 등의 언어에서 이 방식을 사용해볼 수 있습니다. 한 번 타입 추정을 지원하는 언어를 사용해보면 아마 명시적 타입 선언이 필요한 언어로는 절대 되돌아가지 못 할 겁니다. 그만큼 편합니다.