안전함과 불안전함을 마주하라

safe and unsafe

낮은 레벨의 구현 세부사항에 대해 걱정하지 않아도 되면 참 좋을 것입니다. 빈 튜플이 얼마만큼의 공간을 차지하는지 대체 누가 신경쓸까요? 슬프게도 이런 것들은 어떤 때에는 중요하고, 우리는 이런 것들을 걱정해야 합니다. 개발자들이 구현 세부사항에 대해서 걱정하기 시작하는 가장 흔한 이유는 성능이지만 그보다 더 중요한 것은, 하드웨어, 운영체제, 혹은 다른 언어들과 직접적으로 상호작용할 때 이런 세부적인 것들이 올바른 코드를 작성하는 것에 대한 문제가 될 수 있습니다.

안전한 프로그래밍 언어에서 구현 세부사항이 중요해지기 시작할 때, 프로그래머들은 보통 3가지 선택지가 있습니다:

  • 컴파일러나 런타임이 최적화를 수행하도록 코드에 꼼수 쓰기
  • 원하는 구현을 얻기 위해 훨씬 부자연스럽거나 거추장스러운 디자인을 채용하기
  • 구현을 그런 세부사항을 다룰 수 있는 언어로 다시 작성하기

마지막 선택지에서, 프로그래머들이 주로 쓰는 언어는 C 입니다. 이 언어는 C 인터페이스만 정의하는 시스템들과 상호작용하기 위해 보통 필요합니다.

불행하게도 C는 (때때로 좋은 이유로) 사용하기에 엄청나게 불안전하고, 다른 언어들과 협업하려고 할 때 이 불안전함은 증폭됩니다. C와 다른 언어가 어떤 일이 일어날지 서로 동의하고, 서로의 발을 밟지 않게 하기 위해 주의가 필요합니다.

그래서 이것이 러스트와 무슨 상관일까요?

그게, C와 다르게, 러스트는 안전한 프로그래밍 언어입니다.

하지만, C와 마찬가지로, 러스트는 불안전한 언어입니다.

더 정확하게 말하자면, 러스트는 안전한 언어와 불안전한 언어 두 가지를 모두 포함하고 있습니다.

러스트는 안전한 러스트불안전한 러스트 라는 두 개의 프로그래밍 언어의 조합이라고 볼 수 있습니다. 편리하게도, 이 이름들은 말 그대로입니다: 안전한 러스트는 안전하고, 불안전한 러스트는, 음, 그렇지 않죠. 사실 불안전한 러스트는 매우 불안전한 것들을 할 수 있게 해 줍니다. 러스트 개발자들이 하지 말라고 간곡히 부탁하는 것들이지만, 우리는 그냥 무시하고 할 겁니다.

안전한 러스트는 진정한 러스트 프로그래밍 언어입니다. 만약 안전한 러스트만 작성한다면, 타입 안정성이나 메모리 안정성은 절대 걱정할 필요가 없을 겁니다. 달랑거리는 포인터나, 해제 후 사용, 혹은 다른 종류의 미정의 동작은 겪지 않을 테니까요.

표준 라이브러리도 또한 당신에게 바로 쓸 수 있는 도구들을 풍부하게 주어서 당신이 순수하고 자연스러운, 안전한 러스트로 고성능의 응용 프로그램을 만들 수 있게 해 줍니다.

하지만 혹시 당신이 다른 언어에게 말을 걸고 싶을 수도 있습니다. 표준 라이브러리가 노출하지 않은 저수준의 추상화를 작성하고 있을 수도 있죠. 당신이 (순수하게 러스트로 만들어진) 표준 라이브러리를 작성하고 있을 수도 있습니다. 타입 시스템이 이해하지 못하는 것을 해야 할 수도 있고 그냥 좀 비트들에 장난질을 하고 싶을 수도 있습니다. 당신은 불안전한 러스트가 필요할지도 모릅니다.

불안전한 러스트는 안전한 러스트와 아주 흡사합니다. 안전한 러스트의 모든 규칙들과 의미들을 담고 있죠. 다만 추가적으로 절대로 안전하지 않은 것들을 할 수 있게 해 줍니다 (이에 대해서는 다음 섹션에서 다루겠습니다).

이런 구분을 통해 우리는 C와 같은 불안전한 언어의 이점 - 구현 세부사항에 대한 저수준 제어 - 을 얻으면서 완전히 다른 안전한 언어에 통합하려고 할 때 생기는 문제들 대부분을 피할 수 있게 됩니다.

몇몇 문제들이 아직 있긴 합니다 - 대표적으로 타입 시스템이 가정하는 속성들에 대해서 인식하고, 불안전한 러스트와 상호작용하는 어떤 코드에도 그 속성들을 검증해야 합니다. 그게 바로 이 책의 목적입니다: 이런 가정들에 대해서, 또 이것들을 어떻게 관리해야 하는지 가르쳐주는 것이죠.