Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

둘러보기: 새로운 언어 기능, 설계부터 안정화까지

이 장에서는 새로운 언어 기능의 설계와 구현 과정을 차례대로 살펴봅니다. 이 단계 중 일부는 언어 기능에만 해당하지만, 상당수는 라이브러리 기능에도 적용됩니다.

개요

이 장에서 다룰 기능은 매크로용 ? 클리니(Kleene) 연산자입니다. 요컨대, 다음과 같은 코드를 작성할 수 있기를 원합니다:

macro_rules! foo {
    ($arg:ident $(, $optional_arg:ident)?) => {
        println!("{}", $arg);

        $(
            println!("{}", $optional_arg);
        )?
    }
}

fn main() {
    let x = 0;
    foo!(x); // ok! prints "0"
    foo!(x, x); // ok! prints "0 0"
}

요컨대 매크로의 $(pat)? 매처는 다른 정규식 구문과 마찬가지로 “이 패턴은 0번 또는 1번 나타날 수 있음“을 의미합니다.

아이디어를 안정된 Rust 기능으로 만들기까지는 여러 단계를 거쳤습니다. 간단한 목록은 다음과 같습니다. 아래에서 각 단계를 순서대로 살펴보겠습니다. 앞서 언급했듯이, 모든 유형의 기여에 이 단계가 전부 필요한 것은 아닙니다.

  • 아이디어 논의/Pre-RFC Pre-RFC는 기능에 대한 초기 초안 또는 설계 논의입니다. 이 단계는 설계 공간을 어느 정도 구체화하고 아이디어의 여러 장점과 문제점을 파악하기 위한 것입니다. 더 많은 사람에게 아이디어를 공개하기 전에 초기 피드백을 받을 수 있는 좋은 방법입니다. 원래 논의는 여기에서 볼 수 있습니다.
  • RFC 이 단계에서는 검토를 받기 위해 아이디어를 커뮤니티에 공식적으로 제안합니다. RFC는 여기에서 볼 수 있습니다.
  • 구현 아이디어를 컴파일러에 불안정 기능으로 구현하십시오. 원래 구현은 여기에서 볼 수 있습니다.
  • 반복/개선(필요한 경우) 커뮤니티가 nightly 컴파일러와 std에서 기능을 사용해 보면서, 설계 선택에 관해 조정이 필요할 수 있는 추가 피드백이 나올 수 있습니다. 이 기능은 여러 차례의 반복을 거쳤습니다.
  • 안정화 기능이 충분히 무르익으면 Rust 팀 구성원이 안정화를 제안할 수 있습니다. 합의가 이루어지면 안정화가 완료됩니다.
  • 휴식 이제 여러분의 기능은 안정된 Rust 기능입니다!

Pre-RFC와 RFC

참고: 일반적으로 Rust나 생태계에 새로운 기능이나 중대한 변경을 제안하는 것이 아니라면 RFC 절차를 따를 필요가 없습니다. 대신 곧바로 구현으로 넘어가면 됩니다.

RFC를 언제 열어야 하는지에 대한 공식 지침은 여기에서 볼 수 있습니다.

RFC는 제안하려는 기능이나 변경 사항을 자세히 설명하는 문서입니다. RFC는 누구나 작성할 수 있으며, 절차는 Rust 팀 구성원을 포함한 모든 사람에게 동일합니다.

RFC를 열려면 GitHub의 rust-lang/rfcs 저장소에 PR을 여십시오. 자세한 안내는 README에서 볼 수 있습니다.

RFC를 열기 전에 아이디어를 “구체화“하기 위한 조사를 해야 합니다. 성급하게 제안된 RFC는 수락되지 않는 경향이 있습니다. 일반적으로 동기, 영향, 단점, 그리고 다른 기능과의 잠재적 상호작용을 잘 설명할 수 있어야 합니다.

할 일이 많아 보인다면, 실제로 그렇기 때문입니다. 하지만 걱정하지 마십시오! 컴파일러 해커가 아니더라도 pre-RFC를 진행하면 훌륭한 피드백을 받을 수 있습니다. 이는 아이디어에 대한 비공식적인 논의입니다. 이를 진행하기에 가장 좋은 곳은 internals.rust-lang.org입니다. 게시물이 특정한 구조를 따를 필요는 없습니다. 심지어 일관된 아이디어일 필요도 없습니다. 일반적으로 수많은 피드백을 받게 되며, 이를 다시 반영하여 좋은 RFC를 작성할 수 있습니다.

(또 하나의 유용한 팁: RFC 저장소와 internals에서 이전에 제기된 관련 아이디어를 검색해 보십시오. 어떤 아이디어가 이미 검토되었다가 거부되었거나, 나중에 다시 시도하기로 연기된 경우가 많습니다. 이렇게 하면 여러분과 다른 모든 사람의 시간을 절약할 수 있습니다)

이 예시의 경우, pre-RFC 스레드의 한 참여자가 구문 모호성과 가능한 해석 방안을 지적했습니다. 또한 전반적인 피드백은 긍정적인 것으로 보였습니다. 이 경우에는 논의가 꽤 빠르게 수렴했지만, 어떤 아이디어는 훨씬 더 많은 논의가 이루어질 수 있습니다(예: 무려 684개의 댓글을 받은 이 RFC를 참고하십시오!). 그런 일이 생기더라도 낙담하지 마십시오. 이는 커뮤니티가 여러분의 아이디어에 관심이 있지만, 아마도 약간의 조정이 필요하다는 뜻입니다.

우리의 ? 매크로 기능에 대한 RFC도 RFC 스레드에서 어느 정도 논의가 이루어졌습니다. 대부분의 RFC와 마찬가지로 논의만으로는 답할 수 없는 몇 가지 질문이 있었습니다. 결정을 내리려면 기능을 실제로 사용해 본 경험이 필요했습니다. 이러한 질문은 RFC의 “Unresolved Questions”(미해결 질문) 섹션에 나열됩니다. 또한 RFC 논의가 진행되는 동안 논의의 흐름을 반영하도록 RFC 문서 자체를 갱신하고 싶어질 것입니다(예: 새로운 대안이나 선행 연구가 추가될 수도 있고, 제안 자체의 일부를 변경하기로 결정할 수도 있습니다).

결국 논의가 합의에 이르고 다소 잦아든 것으로 보이면, Rust 팀 구성원이 세 가지 가능한 처리 방침 중 하나와 함께 “최종 의견 수렴 기간”(FCP)으로 넘어갈 것을 제안할 수 있습니다. 이는 해당 팀의 다른 구성원들이 RFC를 검토하고 의견을 남기기를 원한다는 뜻입니다. 추가 논의가 이어질 수 있으며, 그 결과 더 많은 변경 사항이나 미해결 질문이 추가될 수 있습니다. 어느 시점에 모두가 만족하면 RFC는 FCP에 들어가며, 이는 사람들이 이의를 제기할 수 있는 마지막 기회입니다. FCP가 끝나면 해당 처리 방침이 채택됩니다. 가능한 세 가지 처리 방침은 다음과 같습니다:

  • 병합(Merge): 기능을 수락합니다. 다음은 우리의 ? 매크로 기능에 대한 병합 제안입니다.
  • 종료(Close): 현재 형태의 이 기능은 Rust에 적합하지 않습니다. 여러분의 RFC가 이렇게 처리되더라도 낙담하지 마시고, 개인적으로 받아들이지 마십시오. 이는 여러분에 대한 평가가 아니라, Rust가 다른 방향으로 나아가겠다는 커뮤니티의 결정입니다.
  • 연기(Postpone): 이 방향으로 나아가는 데 관심은 있지만 지금은 아닙니다. 이는 대부분 해당 Rust 팀이 안정화에 이르는 과정 동안 기능을 이끌어 갈 여력이 없기 때문에 발생합니다. 기능이 팀의 로드맵에 맞지 않을 때 이런 경우가 많습니다. 연기된 아이디어는 나중에 다시 검토될 수 있습니다.

RFC가 병합되면 해당 PR이 RFCs 저장소에 병합됩니다. 기능의 진행 상황을 추적하고 미해결 질문, 구현 진행 상황, 걸림돌 등을 논의하기 위해 rust-lang/rust 저장소에 새로운 추적 이슈가 생성됩니다. 다음은 ? 매크로 기능에 대한 추적 이슈입니다.

실험적 RFC(eRFC)

eRFC는 상위 수준의 필요성은 분명하지만 설계 공간이 너무 넓어 상세한 명세를 미리 확정할 수 없는 복잡한 기능에 사용되는 RFC 프로세스의 변형입니다. eRFC는 최종 설계를 제시하는 대신, 적극적인 실험 기간을 승인하기 위한 상위 수준의 전략을 개괄합니다. 이를 통해 팀은 기능 게이트 뒤에서 기능을 구현하고 실제 데이터를 수집할 수 있으며, 이 데이터는 이후 안정화를 위한 정식 RFC의 근거가 됩니다. 이 프로세스는 코루틴과 같은 주요 기능에 사용되었지만(RFC 2033 참조), 오늘날에는 명시적인 “eRFC” 라벨이 거의 사용되지 않습니다. 현재 프로젝트는 일반적으로 초기 버전에 대해 표준 RFC를 승인한 뒤, 최종 안정화 전까지 nightly 채널을 통해 반복적으로 개선하는 방식을 선호합니다.

구현

컴파일러를 변경하려면 rust-lang/rust 저장소에 PR을 여십시오.

기능, 변경, 버그 수정, 개선 사항에 따라 구현이 비교적 간단할 수도 있고 큰 작업이 될 수도 있습니다. 더 경험이 많은 컴파일러 개발자에게 언제든지 도움이나 멘토링을 요청할 수 있습니다. 또한 기능을 반드시 직접 구현할 필요는 없습니다. 다만 직접 구현하지 않으면 다른 사람이 구현하기까지 시간이 꽤 걸릴 수 있다는 점을 염두에 두십시오.

? 매크로 기능의 경우, 저는 컴파일러에서 매크로 확장과 관련된 부분을 이해해야 했습니다. 개인적으로는 코드의 주석을 개선하는 것이 코드를 제대로 이해했는지 확인하는 데 도움이 된다고 생각하지만, 원하지 않는다면 그렇게 하지 않아도 됩니다.

그런 다음 RFC에 설명된 대로 원래 기능을 구현했습니다. 새로운 기능이 구현되면 기능 게이트 뒤에 놓이며, 이는 해당 기능을 사용하려면 #![feature(my_feature_name)]를 사용해야 한다는 뜻입니다. 기능이 안정화되면 기능 게이트가 제거됩니다.

대부분의 버그 수정과 개선 사항에는 기능 게이트가 필요하지 않습니다. 변경이나 개선 사항을 그대로 적용하시면 됩니다.

PR을 열고 병합하는 방법에 대한 정보는 PR 생명주기를 참조하십시오.

새로운 기능 같은 것을 작업하는 것이 아니라면(예: 버그를 수정하는 경우) 이것으로 끝입니다! 기여해 주셔서 감사합니다 :)

구현 다듬기

사람들이 nightly에서 새 기능을 사용해 보며 경험을 쌓으면서 사소한 변경이 제안되거나 미해결 질문이 해결될 수 있습니다. 업데이트나 변경은 위에서 설명한 것처럼 다른 변경 사항을 구현할 때와 같은 절차를 거칩니다(즉, PR을 제출하고, 리뷰를 거치고, @bors를 기다리는 등).

어떤 변경은 FCP와 Rust 팀 구성원의 검토가 필요할 만큼 중대할 수 있습니다.

? 매크로 기능의 경우, 최초 구현 이후 몇 차례의 반복 작업을 거쳤습니다: 1, 2, 3.

그 과정에서 ?가 구분자를 받지 않도록 결정했으며, 이는 이전에 RFC에 미해결 질문으로 나열되어 있던 사항입니다. 또한 모호성 해소 전략도 변경했습니다. 다른 반복 연산자(예: + 또는 *)에서 ?를 구분자 토큰으로 사용하는 기능을 제거하기로 결정했습니다. 하지만 이는 호환성을 깨는 변경이었기 때문에 에디션 경계를 넘어서 적용하기로 결정했습니다. 따라서 새 기능은 2018 에디션에서만 활성화할 수 있습니다. 원래 RFC와의 이러한 차이점 때문에 또 한 번의 FCP가 필요했습니다.

안정화

마지막으로, 이 기능이 nightly에서 한동안 무르익은 뒤 언어 팀 구성원 한 명이 안정화를 발의했습니다.

다음 내용을 포함하는 안정화 보고서를 작성해야 합니다.

  • 동작에 대한 간략한 설명과 RFC와의 차이점
  • 영향을 받는 에디션과 그 방식
  • 흥미로운 측면을 보여 주는 몇 가지 테스트에 대한 링크

이 기능의 안정화 보고서는 여기에 있습니다.

그 후 기능 게이트를 제거하여 (2018 에디션에서) 기능을 기본적으로 활성화하는 PR이 만들어집니다. 릴리스 노트에 이 기능에 대한 설명이 추가됩니다.

기능을 안정화하는 단계는 기능 안정화하기에서 확인할 수 있습니다.