TECH 으로 돌아가기
TECH HACKER NEWS 오늘 7분 읽기 27 READS

러스트, Pin을 대체할 Move·Forget 트레잇으로 '움직이지 않는 타입'을 노린다

러스트, Pin을 대체할 Move·Forget 트레잇으로 '움직이지 않는 타입'을 노린다
SOURCE IMAGE · HACKER NEWS

러스트 프로젝트 목표(Rust Project Goals)에 2026년 과제로 올라온 이 제안은 언어의 오래된 두 가지 암묵적 전제를 손보려 한다. 지금까지 러스트는 모든 값이 메모리에서 이동(move)될 수 있고, mem::forget을 통해 소멸자를 실행하지 않고 잊혀질(forget) 수 있다고 가정해 왔다. 대입 연산이 값을 이동시키고 mem::forget이 안전한 함수라는 점은 언어 곳곳에 녹아 있는 설계다. 제안의 골자는 이 능력들을 타입 수준에서 명시적으로 표현하는 새로운 오토 트레잇을 도입해, 필요하다면 타입이 스스로 그 능력을 포기할 수 있게 만드는 것이다. Move와 Forget이라는 이름이 붙은 이 트레잇들은 '가능한 연산'을 긍정적으로 기술하며, 기본 계층에서는 아무 특별한 능력도 없는 타입에서 출발해 필요한 능력을 위로 쌓아 올리는 방식을 취한다.

왜 지금 이 문제가 불거지나

두 가지 실무적 동기가 명확하다. 첫째는 이동 불가능한 타입이다. 상당수의 async 퓨처는 자기 자신을 참조하는 자기참조(self-referential) 구조를 갖고 싶어 하지만, 자기참조 타입은 메모리 주소가 바뀌면 내부 포인터가 깨지므로 안전하게 이동시킬 수 없다. 러스트의 현재 해법은 Pin이다. 그런데 Pin은 이동 불가능성을 '타입의 속성'이 아니라 '장소(place)의 속성'으로 인코딩한다. 즉 값 자체가 아니라 값이 놓인 위치에 제약을 건다. 제안 문서는 이 접근이 상당한 복잡성을 낳는다고 지적하며, 리눅스 커널처럼 자기참조 구조가 흔한 시스템에서 Pin이 안전한 초기화를 표현하는 데 어려움을 겪는다는 점을 근거로 든다.

둘째는 소멸자 실행 보장이다. 어떤 타입은 정리 전에 반드시 소멸자가 돌아야 한다. 커밋이나 롤백을 요구하는 트랜잭션 타입, 스코프를 벗어나기 전에 반드시 join해야 하는 태스크 핸들이 그런 예다. 하지만 mem::forget이 안전 함수인 이상 러스트는 소멸자가 반드시 실행된다고 보장할 수 없다. 이 한계 때문에 async에서 안전한 스코프드 스폰(scoped spawn) 같은 패턴이 막혀 있다. 스폰된 태스크가 부모 스코프의 데이터를 빌려 쓰는 구조에서, 핸들을 forget해 버리면 태스크가 스코프보다 오래 살아남아 이미 사라진 참조에 접근할 수 있기 때문이다.

Move와 Forget이 여는 것

Move 트레잇은 이동 가능성을 타입의 속성으로 되돌린다. !Move인 타입은 이동할 수 없고 존재하는 내내 안정적인 주소를 유지해야 한다. 제안자들은 이것이 Pin보다 단순하다고 본다. 제약이 장소가 아니라 타입에 붙기 때문이다. 다만 이런 이동 불가 타입을 실제로 만들어 내려면 값을 제자리에서 초기화하는 in-place 초기화 작업(#t-lang/in-place-init)에 기대야 한다. Forget 트레잇은 타입이 forget 대상이 되기를 거부할 수 있게 한다. !Forget이 있으면 앞서 말한 안전한 스코프드 스폰을 구현할 수 있다. 핸들의 소멸자가 태스크를 join하고, 그 핸들은 애초에 forget될 수 없으므로 join이 반드시 일어난다. 지금은 안전한 러스트로 표현할 수 없는 패턴이 열리는 셈이다.

이 작업은 앞서 진행된 Sized 계층(Sized hierarchy) 작업이 놓은 선례를 따른다. Sized 작업은 '모든 타입은 컴파일 시점에 크기를 알 수 있다'는 보편 가정을 완화해 스케일러블 벡터나 extern 타입을 지원했다. 이번 제안은 같은 패턴을 '모든 타입은 이동 가능하다', '모든 타입은 forget 가능하다'는 두 가정에 적용한다. 즉 트레잇 계층을 통해 예외를 허용하는 방식이다.

Pin과의 관계, 그리고 한계

주목할 점은 이 제안이 Pin을 보완하려는 것이 아니라 대체하려 한다는 것이다. 문서는 2025H2의 Pin 에르고노믹스 실험 지속과 대비하며, 문제는 언어를 바꿔 Pin을 잘 쓰게 만드는 데 있는 게 아니라 Pin이라는 인코딩 방식 자체에 있다고 못 박는다. 최종 목표는 러스트에서 Pin을 완전히 폐기하는 것이다. 러스트가 영원한 하위 호환성을 약속하는 이상, pin을 &나 mut에 준하는 언어 요소로 격상시키면 그것을 영구히 떠받쳐야 한다. 폐기가 목표인 물건을 언어의 일부로 굳혀서는 안 된다는 것이 Move를 보완이 아닌 대안으로 규정하는 이유다. 또한 Pin의 접근으로는 Trait과 PinnedTrait처럼 트레잇이 중복 정의되는 문제가 남는데, Drop만은 일회성 오버로드로 특수 처리되는 예외로 남는다.

실무자 입장에서 유의할 지점은 범위다. 올해 과제에서 Future 트레잇을 바꾸거나 갱신하는 일은 명확히 제외된다. Future는 Pin에 의존하는 유일한 안정화된 트레잇이라 Move로 옮기려면 별도의 마이그레이션 시나리오가 필요하고, Pin 의존 외에도 열 개가 넘는 다른 문제를 안고 있어 독립 프로젝트로 다루는 편이 낫다는 판단이다. 계획은 컴파일러에 MVP를 구현하고 RFC를 작성한 뒤 리눅스 커널에서의 실제 검증으로 실현 가능성을 확인하는 순서로 짜여 있다. 다시 말해 이번 목표는 완성된 기능 발표가 아니라 방향 전환의 실험 단계에 가깝다. async 라이브러리와 임베디드·커널 영역에서 자기참조 구조나 안전한 태스크 수명 관리를 다루는 개발자라면, Pin 중심의 현재 관행이 중장기적으로 어떻게 바뀔지 지금부터 지켜볼 가치가 있다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://github.com/rust-lang/rust-project-goals/blob/main/sr...
SHARE
처리 중...