Rust가 C++를 대체할 수 있을까?

IT 관련 뉴스를 보다 보면, Rust (러스트) 언어가 자주 언급되는 것을 볼 수 있습니다. 그런 기사를 보면, 여러 기업 (Google, AWS 등)과 프로젝트(Deno, Redox 등)의 개발 언어가 C++에서 Rust로 대체 또는 사용된다는 내용을 볼 수 있습니다. (심지어 Linux 커널에도 러스트가 도입되는 계획이 있습니다.)

아마 "Rust vs C++"가 주제인 논쟁이 자주 벌어지는 이유는, 두 언어의 사용처가 비슷하기 때문이겠죠. 이번 글은 러스트는 C++ 대신 사용하기 좋으며, 정말로 C++를 대체할 수 있을까? 에 대한 글입니다.

들어가기 앞서, 필자는 C++ 전공이 아니기 때문에 틀린 정보가 있을 수 도 있습니다. 이에 대해 반박하셔도 좋습니다.

러스트를 접해보았다면, C++과 상당히 비슷한 부분이 상당히 존재한다는 것을 알 수 있습니다. 안전한 러스트에선 전반적으로 RAII (Resource Acquisition Is Initialization) 패턴을 사용합니다. 이는 C++에서 유래되었습니다.

안전한 러스트

여기서 안전한 러스트는 다음과 같은 보장을 말합니다:

  • 소유권과 참조, 수명을 컴파일 타임에 검사합니다.
    • 소유권과 수명은 러스트의 가비지 컬렉터를 대신하여, 메모리 관리를 위해 고려된 생소한 개념입니다. (C++에도 unique_ptr 등의 소유권 개념이 있긴 합니다만.)
    • * 소유권과 수명을 이 글에선 서술하지 않습니다. 모든 값은 소유권과 수명을 가지고 있고, 이의 유효성을 컴파일 타임에 검사함으로써, 런타임 시 안전성을 보장한다는 것만 알아둡시다.
    • 참조는 후술할 로우 포인터에 몇가지 안전성을 보장하는 시스템을 적용한 러스트의 기능입니다. 최종적으로는 로우 포인터로 컴파일됩니다.
  • null이 없습니다. (= null pointer 에러가 없습니다.)
  • 가변성을 컴파일 타임에 검사합니다. 불변의 변수는 수정이 불가능하며, mut 키워드를 통해 가변 변수를 선언할 수 있습니다.
  • 예외 대신 Result<T, E>를 사용합니다. (패닉(panic)이 존재하나, 디버그 (또는 테스트)가 아니라면, 프로그래머의 잘못이 아닌 이상 발생하진 않습니다.)

안전하지 않은 러스트

러스트가 안전하기만 하다고 서술하지 않고, 안전한 러스트라 서술한 이유는, 고급 기능인 안전하지 않는 (unsafe) 러스트가 존재하기 때문입니다.

안전하지 않는 러스트는 다음과 같은 기능을 가집니다.

  • 로우 포인터(raw pointer)를 역참조 할 수 있습니다. (= null이 발생할 수 있습니다.)
  • 안전하지 않는 함수 호출할 수 있으며, 안전하지 않는 트레잇을 구현할 수 있습니다.
  • 가변 정적 변수를 수정할 수 있습니다. (여기선 다루지 않습니다.)

즉, 러스트는 메모리 안전을 보장으로 하나, 이를 강제하지 않는 안전하지 않는 러스트를 가지고 있습니다. 이 글은 러스트의 unsafe를 다루는 내용은 아니니, 이렇게 2가지의 러스트가 있다는 것만 알아둡시다. 또한 러스트는 C++의 거의 모든 (언어 레벨, 표준 라이브러리) 기능을 가지고 있습니다.

예를 들어, C++의 shared_ptr은 러스트의 Rc<T> (가변일 경우 Rc<RefCell<T>> 등), thread-safe에서 사용할 경우 Arc<Mutex<T>> 또는 Arc<RwLock<T>>) 등이 있습니다.

이를 바탕으로 C++와 러스트를 비교해봅시다:

러스트의 특징과 단점:

  • 위에서 설명했듯이, (안전한 러스트에서) 메모리 안전을 보장합니다.
  • 가비지 컬렉터가 없습니다.
  • null이 없습니다.
  • 병렬 프로그래밍, 함수형 프로그래밍, 시스템 프로그래밍을 지원합니다.
  • Cargo라는 패키지 매니저로, 강력한 패키지 관리를 지원합니다.
  • C++에 비해, 문서(자료)가 많이 없습니다.
  • 생태계가 C++에 비해 매우 작습니다.

C++의 특징과 단점:

  • C 언어의 절차적 프로그래밍을 기반으로 객체지향 프로그래밍, 템플릿 등을 사용하는 일반화 프로그래밍을 지원합니다.
  • 러스트와 반대로, 문서(자료)가 많으며, 한국어 자료 또한 매우 많아서, 자료를 참고하기 좋습니다.
  • 생태계가 상당히 구축되어있습니다.
  • 러스트에 비해 메모리 관리가 어렵습니다 (메모리 안전을 보장하지 않습니다.) (물론 스마트 포인터 unique_ptr (러스트의 소유권과 유사), RAII 패턴 등을 이용하면 어느 정도 방지할 수 있긴합니다만,)
  • 생산성이 안 좋으며, 디버깅 및 유지보수가 힘듭니다.
  • 이렇다 할 패키지 매니저가 없습니다. (컴파일러가 러스트 처럼 단일하지 않습니다.)

둘 모두 서술되어있는 항목보다 더 많을 수도 있습니다. 이렇게만 보면, 러스트가 훨씬 좋아 보이는데, 그런데도 왜 아직까지 러스트보다 C++이 더 많이 쓰이는 걸까요?

러스트의 생태계

위에서 말한 대로, 러스트는 C++에 비해 생태계가 매우 매우 작습니다. 이 뜻은 문서(자료), 커뮤니티 등이 C++에 비해 부족하다는 뜻이며, 결국 이는 이번 주제 (C++ vs Rust)에서 결정적인 증거가 됩니다.

여러 러스트 사용자들이 생태계를 구축하기 위해, 노력하고 있긴합니다.

당장 한국만 해도 한국 러스트 사용자 그룹, Rust Book 한국어 번역 등의 노력이 보이긴 하나, C++에 비빌정도는 택도 안됩니다.

절대 C++를 대체할 수 없는 것일까?

그럼 러스트는 절대 C++를 대체할 수 없는 것일까요? 이건 또 아닙니다.

C++는 사실상 완벽한 생태계를 가지고 있고, 러스트는 생태계를 구축하는 중입니다.

이 뜻은 러스트가 C++를 충분히 대체할 수 있다는 얘기와 같습니다. 생태계가 작긴 하지만, 러스트는 표준 라이브러리 및 언어 문서화가 상당히 잘 되어있습니다.

그럼 영어도 능숙하게 할 수 있고, 메모리 안전성도 보장하고 싶으니, 러스트를 쓰겠다고 하는 사람도 분명 있겠죠. 언어의 선택은 본인의 자유이며, 언어마다 각자 장단점이 있긴 하지만, 러스트와 C++에 대해 한 가지만 말하고 글을 끝내겠습니다.

러스트는 메모리 안전을 보장으로 합니다. 하지만 그것에 완벽하다는 것은 아닙니다:

또한 C++은 발표된 지 무려 37년이 넘은 언어입니다. (러스트는 첫 릴리즈가 12년 전) 그런데도 메모리 안전성을 보장하지 않는 C++를 37년이 넘게 써왔습니다.

결국 이것은 프로그래머들이 큰 문제없이 써왔다는 것이며, 이는 곧 프로그래머에 따라, 메모리 안전을 보장할 수 있다는 뜻으로 해석할 수 있습니다. C++가 잘못된 언어가 아납니다. 러스트가 완벽한 언어는 아니며, 모든 언어는 장단점을 가지고 있습니다.

대기업 또는 큰 프로젝트에서 러스트로 대체한다는 건, 러스트의 장점에 반한 경우이며, 아직 C++로 작성되어있는 (또는 작성될) 프로젝트는 이보다 더 많습니다. (심지어 러스트로 대체한다는 계획을 절대 세우지 않는 프로젝트도 있을 겁니다.)

지금 당장은 러스트는 C++를 대체하기엔 어렵습니다. 하지만, 앞으로의 상황을 우린 알지 못합니다. 언젠간 러스트의 생태계가 커지고, C++를 대체하는 날이 올 수 도 있을겁니다.

이 주제에 대해 중립을 띄고 싶다면, 둘다 배워두시는 것도 좋은 방법입니다.