Rue 둘러보기: Rust보다 쉽고 Go보다 매서운 언어
새로운 시스템 프로그래밍 언어 소식이 또 하나 들려왔는데요. 이름은 Rue, 만든 사람은 The Rust Programming Language 책의 공동 저자로 잘 알려진 Steve Klabnik입니다. 흥미로운 점은 Klabnik이 혼자 만든 게 아니라 Claude와 짝을 지어 짧은 기간에 컴파일러 뼈대를 세웠다는 사실이죠.
이번 글에서는 Rue가 어떤 자리에 서고 싶어 하는지, 그리고 Rust 소유권을 어떤 식으로 다시 풀어낸 건지 살펴봅니다. 아직 초기 단계의 실험이지만, 시스템 언어가 어떤 방향으로 더 갈 수 있을지 엿볼 만한 재미있는 사례입니다.
Rue가 등장한 배경
Klabnik은 오래전부터 자기 손으로 언어 하나쯤은 만들어 보고 싶다는 생각을 품고 있었다고 합니다. 다만 정규직과 가족 일정 사이에서 컴파일러 한 채를 처음부터 짤 시간은 좀처럼 나오지 않았죠. 그러다 Claude를 진지하게 써 보고 나서 “혹시 혼자라도 가능하지 않을까?”라는 호기심이 생겼고, 그 호기심을 검증해 보려고 시작한 결과물이 Rue입니다.
본인은 한동안 LLM에 회의적이었다고 털어놓는데요. 다만 코드 작성이라는 좁은 영역에 한정해서는 “이제 충분히 쓸 만한 도구가 됐다”는 결론에 이르렀다고 합니다. 그래서 Rue는 단순히 새 언어 하나를 더 던지는 시도라기보다, “한 사람과 LLM이 짧은 시간에 어디까지 갈 수 있는가”를 직접 자기 손으로 측정해 보는 실험이기도 한 셈이죠.
이름에 담긴 의미도 재미있습니다. Ruby에서 시작해 Rust로 이어지는 “Ru” 계보를 잇는 동시에, 영어 표현 “to rue the day(그날을 후회하다)“의 어두운 톤도 함께 끌어왔다고 본인이 직접 밝혔는데요. Rust도 원래 곰팡이 이름에서 따왔으니, 이름의 결을 비슷하게 맞춘 셈입니다.
Klabnik은 이 프로젝트를 두고 “그냥 재미로 하는 일이고, 커뮤니티를 키우거나 기여자를 모으는 것이 목표가 아니다”라고 못 박았습니다. 진지한 대안이라기보다 한 사람이 AI 도구를 곁에 두고 어디까지 갈 수 있는지 시험해 보는 무대에 가깝죠.
Rust보다 높고 Go보다 낮은 자리
Rue가 스스로 잡은 자리는 공식 사이트에서 한 줄로 요약됩니다. “Rust보다는 높은 수준이고 Go보다는 낮은 수준인 언어.” 이 한 문장에 Rue의 모든 설계 결정이 녹아 있는데요.
Rust가 메모리 안전성을 컴파일 타임에 보장한다는 점에서는 분명 성공했지만, 빌림 검사기와 라이프타임 표기 같은 장치 때문에 처음 배우는 사람에게는 가파른 절벽처럼 느껴진다는 평이 많습니다. 반대로 Go는 문법이 단순하고 학습 곡선이 완만한 대신, 가비지 컬렉터를 끼고 있어서 시스템 자원을 빠듯하게 다루는 영역에는 잘 맞지 않습니다.
Rue는 이 두 지점 사이의 빈 자리를 노립니다. 가비지 컬렉터 없이 네이티브 코드로 컴파일되는 성능을 유지하면서도, 일상적인 코드를 짤 때 마주치는 마찰은 줄여 보겠다는 그림이죠. 가상 머신도, 인터프리터도, 가비지 컬렉터도 없이 x86-64와 ARM64 기계어로 곧장 컴파일되는 점은 Rust와 같습니다.
물론 “더 쉬운 Rust”를 표방하는 시도가 처음은 아닙니다. 같은 자리에서 종종 거론되는 Zig도 시스템 자원에 가까운 코드를 작성하면서 Rust보다 단순한 인지 부담을 노리고 있죠. Rue가 이들과 갈라지는 지점은 빌림 검사기를 들어내는 대신 소유권 모델 자체를 다른 모양으로 다시 짜 보겠다는 결단에 있습니다.
첫 코드: 피보나치
말로 길게 풀기 전에 Rue 코드가 어떻게 생겼는지 먼저 보는 편이 빠릅니다. 공식 사이트에 올라와 있는 피보나치 예제를 가져와 보겠습니다.
fn fib(n: i32) -> i32 {
if n <= 1 {
n
} else {
fib(n - 1) + fib(n - 2)
}
}
fn main() -> i32 {
let mut i = 0;
while i < 10 {
@dbg(fib(i));
i = i + 1;
}
0
}
처음 보면 거의 Rust 같습니다. fn, let mut, i32, 표현식 기반의 if 같은 요소가 그대로 옮겨와 있죠. 함수의 마지막 표현식이 반환값이 되는 규칙도 같습니다.
차이는 디테일에서 나타나는데요. main이 () 대신 i32를 반환해서 종료 코드를 직접 돌려주는 점이 눈에 띕니다. @dbg(...) 같은 @ 접두 호출은 디버깅용 내장 도구를 부르는 모양새인데, Rust의 매크로 dbg!()와 비슷한 자리에 서 있습니다. C나 Go를 써 본 사람이라면 i = i + 1의 친숙한 흐름도 그대로 받아들일 수 있고요.
핵심은 “Rust를 알면 거의 그대로 읽힌다”는 데 있습니다. Klabnik 본인도 학습 곡선을 부드럽게 가져가고 싶다고 여러 번 강조했는데, 첫 인상부터 그 결을 따라가고 있는 셈이죠.
네 가지 소유권 모드
Rue가 Rust와 갈라지는 지점은 본격적으로 데이터 다루는 방식에 있습니다. Rust는 모든 값이 기본적으로 단일 소유자를 가진다는 한 가지 규칙을 깔고, 필요할 때마다 참조 카운팅이나 Arc 같은 도구를 덧씌우는 방식이죠.
Rue는 처음부터 네 가지 소유권 모드를 표면에 드러냅니다. 값 모드, 친화 모드, 선형 모드, 참조 카운팅 모드인데요. 이름은 거창해 보이지만 결국 “이 값이 어떻게 복제되고 어떻게 폐기되는가”를 네 가지 색깔로 나누어 두었다고 보시면 됩니다.
가장 먼저 값 모드는 Rust의 Copy와 비슷합니다. 정수나 불린처럼 작고 단순한 값을 넘길 때마다 자동으로 복사되죠. 친화 모드는 Rust의 기본 소유권과 거의 같은 자리인데, 값을 한 번만 쓸 수 있다는 제약이 붙습니다. 한 번 다른 곳으로 넘기면 원래 자리에서는 더 사용할 수 없죠.
선형 모드는 친화 모드보다 한 발 더 엄격합니다. 반드시 정확히 한 번 사용해야 하고, 버려서도 안 됩니다. 파일 핸들이나 잠금처럼 명시적으로 닫아야만 하는 자원에 잘 어울리는 모델인데요. “잊고 안 닫았더니 누수가 났다”는 사고를 컴파일러 단에서 잡아 줄 수 있습니다. 참조 카운팅 모드는 이름 그대로 런타임에 참조 수를 세서 마지막 참조가 사라지는 순간 자원을 정리합니다. Rust에서는 Rc나 Arc로 별도로 끌어와야 하는 모델이 Rue에서는 일등 시민이죠.
이렇게 모드를 펼쳐 두면 코드를 읽는 사람이 “이 값은 이런 식으로 흐르는구나”를 한눈에 파악하기가 쉬워집니다. Rust에서 같은 표현을 하려면 타입 자리에 Rc<T>, Arc<Mutex<T>>처럼 래퍼가 줄줄이 따라붙는데, Rue는 그 정보를 모드로 빼서 시각적 잡음을 줄여 보겠다는 시도로 읽힙니다.
한 가지 짚어 둘 점은, 네 모드가 모두 컴파일 타임에 결정되는 정적인 분류라는 사실입니다. 같은 함수 안에서 어떤 값은 친화 모드로, 어떤 값은 참조 카운팅 모드로 다루도록 섞어 쓸 수 있고, 컴파일러는 각 자리에서 그 모드의 규칙을 강제합니다. Rust에서 “이 값을 공유 소유로 가져갈까, 단일 소유로 갈까”를 고민하던 자리가, Rue에서는 “어떤 모드로 선언할까”라는 비슷하지만 조금 더 평평해진 선택으로 바뀌는 셈이죠.
inout으로 풀어낸 빌림
Rust를 처음 배울 때 가장 자주 부딪히는 벽이 빌림 검사기입니다. &와 &mut, 라이프타임 매개변수 'a, “값을 빌렸는데 원본이 먼저 사라지면 안 된다”는 규칙들이 한꺼번에 몰려오죠. 이걸 무리 없이 익히는 데까지 시간이 꽤 걸립니다.
Rue는 이 문제를 우회하려고 Swift에서 영감을 받은 inout 매개변수를 도입했습니다. 함수에 값을 inout으로 넘기면, 함수 호출이 진행되는 동안에는 함수가 그 값을 잠시 소유하고, 함수가 돌아올 때 호출한 쪽에 다시 돌려주는 방식입니다. 빌리는 게 아니라 “잠시 맡기고 돌려받는” 모델이라고 생각하시면 가깝죠.
이 모델의 좋은 점은 라이프타임 표기가 필요 없다는 것입니다. “값이 함수 안에 있는 동안에는 호출자 쪽에서 못 본다”는 규칙이 자연스럽게 보장되기 때문에, “이 참조가 저 참조보다 오래 살아야 한다”는 식의 관계를 사람이 직접 적어 줄 일이 사라집니다. Rust로 자료구조를 짜다가 라이프타임 매개변수가 두세 개 붙어 머리가 복잡해진 경험이 있다면, 이 차이가 얼마나 시원할지 짐작하실 수 있을 거예요.
물론 공짜는 없습니다. Rust의 빌림이 표현할 수 있는 동시 읽기, 부분 빌림 같은 미세한 시나리오 중 일부는 inout 모델만으로는 다루기 어려울 수 있습니다. Rue가 이 부분을 어떻게 메워 갈지가 앞으로의 관전 포인트가 되겠죠.
컴파일러와 런타임
Rue의 컴파일러는 Rust로 짜였습니다. 빌드 스크립트와 일부 도구를 빼면 코드의 절대 다수가 Rust 코드인데요. Klabnik의 글에 따르면 Claude와 페어를 짜고 며칠 안에 십만 줄 단위의 코드를 작성해 컴파일러 뼈대를 세웠다고 합니다.
목표 플랫폼은 x86-64와 ARM64 두 갈래이고, 둘 다 가상 머신을 거치지 않고 곧장 기계어로 떨어집니다. 가비지 컬렉터가 없으니 런타임도 가볍고, 시작 비용도 사실상 없는 수준이죠. 이 점은 Rust와 같은 자리이고, Go와는 다릅니다.
표준 라이브러리는 이제 막 모양을 갖추기 시작한 상태입니다. 정수, 불린, 배열, 구조체 같은 기초 타입과 함수, 식, 문 같은 기본 문법은 언어 명세에 정리되어 있지만, 실제로 응용을 짜기에는 빠진 조각이 아직 많습니다. 그래도 명세 문서를 0.x 버전부터 차근히 쌓아 가고 있다는 점은 인상적이죠.
빌드 결과물도 Rust로 만든 단일 바이너리에 가깝습니다. 컴파일러를 받아서 .rue 소스를 입력으로 던지면 곧장 실행 파일이 떨어지는 흐름이고, 별도의 런타임을 함께 배포할 필요가 없습니다. 이런 결과물 모양은 Go의 단일 바이너리 배포 경험과 비슷한 매력을 줍니다. “한 파일만 옮기면 끝”인 배포 모델은 실제로 운영을 해 본 사람에게 적지 않은 안도감을 주거든요.
아직은 실험 단계
여러 매력 포인트가 있긴 해도, Rue는 누가 봐도 초기 단계의 프로젝트입니다. 공식 사이트에서도 “지금은 실제 사용에 적합하지 않으며, 버그와 누락된 기능, 변경 사항을 예상하라”고 명확히 적어 두었죠. 패키지 매니저, 디버거, 표준 입출력 라이브러리 같은 일상적인 도구들도 아직 본격적으로 갖춰지지 않은 상태입니다.
그러니 “내일부터 Rue로 사이드 프로젝트를 짜자”는 결정은 시기상조입니다. 지금은 차라리 다음 두 가지 관점에서 들여다보시는 편이 어울립니다.
첫째, 시스템 언어 설계의 다음 실험이 어떤 모습일지 미리 엿보는 창입니다. Rust가 “이 정도까지 컴파일러가 잡아 줄 수 있다”는 한계를 끌어올렸다면, Rue는 “그 안전성을 더 적은 인지 부담으로 풀어낼 수 있는가”를 묻고 있죠. 답이 어떻든 이 질문 자체가 흥미롭습니다.
둘째, AI 보조 도구가 컴파일러 같은 깊이 있는 시스템을 어디까지 도와줄 수 있는지를 확인해 볼 수 있는 사례입니다. Klabnik은 한 사람과 LLM이 짧은 기간에 컴파일러를 세울 수 있음을 증명하려 했고, 적어도 작동하는 컴파일러를 굴리는 단계까지는 도달했습니다. 이 협업 패턴이 다른 영역으로 어떻게 번져 갈지 지켜볼 만합니다.
마치며
Rue는 한 줄로 정리하면 “Rust의 안전성을 더 부드러운 표면으로 옮겨 보려는 실험”입니다. 네 가지 소유권 모드를 일등 시민으로 두고, 빌림 대신 inout을 끌어와 라이프타임 표기에서 벗어나려 한 점이 가장 두드러진 시도죠. 가비지 컬렉터 없이 네이티브로 떨어지는 컴파일 모델은 그대로 가져오면서, Rust에서 가파르게 느껴지던 학습 곡선을 어떻게 깎아 낼 수 있을지를 한 번에 보여 주려고 합니다.
당장 실무에 들이기에는 너무 이른 단계지만, Rust의 다음 세대 시스템 언어가 어떤 그림이 될 수 있을지 궁금하다면 한 번쯤 들여다볼 가치가 있습니다. 특히 Rust의 소유권을 한 번 거쳐 본 사람이라면 Rue의 설계 결정이 어떤 마찰을 줄이려는 시도인지 더 또렷하게 보일 거예요.
더 자세한 내용은 Rue 공식 사이트와 언어 명세를 참고하세요.
This work is licensed under
CC BY 4.0