타입 시스템이 허락한 레이스
서버 회는 부채로 끝나 있었다: 가변 Map이 타입 검사기의 축복을 받아 thread 경계를 넘고, 부하 아래서 쓰기를 잃었다. 그 상환은 두 수정으로 이루어졌고, 둘째는 「첫째가 듣지 않았다」고 우겨야만 찾을 수 있었다. 가변 컨테이너는 이제 Send도 Sync도 아니다 —— 그리고 컴파일 경로는, 실은 안전 해석을 한 번도 돌리지 않고 있었다: interpreter가 거부하는 프로그램이, 컴파일러는 무사통과였다.
이 프로젝트가 스스로에게 지우는 규칙은, 실측된 soundness의 구멍은 다른 어떤 일보다 우선한다, 이다. 그래서 서버 회의 부채는 어떤 새 기능보다 먼저 만기를 맞았다: 타입 시스템은 가변 Map의 thread 간 공유를 허락했고, Map은 레이스했다. 설계가 추궁당한 것이 아니다. 언어의 병행성 규율은, 포획되는 모든 값을 Sync(공유하라), Send(move하라), 어느 쪽도 아님(포획을 거부하라)으로 분류하고, region에 묶인 가변 컨테이너는 늘 thread-local일 작정이었다 —— 문서는 그 말 그대로 적고 있었다. 분류기가 그 의도를 구현하지 않았을 뿐이다. 범용 규칙은 컨스트럭터를 타입 인자로 판정한다. 컨테이너의 첫 인자는 region marker이고, region marker는 미해결 타입 변수이고, 규칙은 미해결을 안전으로 간주했다. 하필 최악의 자리에서의 낙관 —— runtime이 그 자리에서 고쳐 써지는 락 없는 배열인, 바로 그런 종류의 값에서.
아무것도 바꾸지 않은 수정
수리는 세 줄로 보였다: Map, Vec, string builder는, 범용 규칙이 인자를 보기 전에, 명시적으로
Send도 Sync도 아니다. owned-vector 타입은 move 의미론을 지킨다 —— drop 타입이고, 구성부터 단일
소유자이고, move로써 thread를 넘는 것이야말로 그 존재 이유다. channel은 Send이자 Sync인 채. 축복받은
패턴이기 때문이다. 기분 좋아야 할 순간은, 서버의 naive한 초고를 다시 컴파일해 실패하는 모습을 바라보는
것이었다. 통과해 버렸다. 분류기는 옳고, move 검사기도 옳고, 그런데도 프로그램은 빌드되었다 —— 즉
문제는 이제, 해석이 무엇을 결론하는가가 아니라, 누군가 해석에게 묻고 있는가였다.
한 번도 돌지 않았던 검사
답은, 인프라 버그만이 가지는 종류의 민망함이었다. interpreter의 파이프라인은 전열을 돌리고 있었다:
타입 추론, 다음에 channel 요소의 Send 의무, 대여 충돌 검사, spawn 포획의 move 해석. 컴파일의 입구
—— C・LLVM・WebAssembly 세 backend가 공유하는 —— 는, 타입 추론을 하고 그대로 코드 생성으로 나아가고
있었다. 언어가 병행성과 region을 위해 세운 안전 해석 전부가, 바이너리를 만들 때는 그저 건너뛰어지고
있었다. region의 대여를 spawn한 thread에 포획시키는 프로그램은, mere run에는 거부되고, mere -c에는
말없이 빌드된다 —— 그리고 두 경로가 존재한 이래 줄곧 그랬다. 수정은, 어느 backend가 프로그램을 보기
전에, 컴파일 경로에도 같은 세 해석을 돌리는 것. 이로써 비로소 naive한 서버 초고는 컴파일에 실패했다.
처음부터 그래야 했던 에러와 함께: Map은 thread 경계를 넘어 포획할 수 없다, 그것은 Send도 Sync도
아니다.
증명으로서의 서버
이 회를 옳게 닫는 세부가 둘 있다. 첫째, actor model 서버 —— 세 화 전의 우회책 —— 는 엄격해진 규칙 아래서 무변경인 채 컴파일된다. channel은 Send이고, store는 thread를 넘지 않기 때문이다: 그 우회책은, 처음부터 줄곧, 지금 타입이 강제하는 설계 그 자체였다. 그것은 테스트 스위트에, 축복받은 패턴이 살아남는다는 살아 있는 증명으로 앉아 있다. 둘째, 정직한 비대칭: 이 구멍을 찾은 것은 감사가 아니라, 레이스한 한 편의 프로그램이었다. dogfood 법이 의도대로 기능했다는 것이고 —— 동시에, 세운 것만 찾을 수 있다는 경계이기도 하다. soundness의 주장은 모든 프로그램에 대한 주장이고, dogfood가 검사하는 것은 언제나 한 편 더일 뿐이다. 타입 시스템이 옳은 자리에서 「아니오」라고 말하게 된 지금, 남은 부채는 최대의 그것 —— 결코 돌아오지 않는 메모리 —— 이고, 다음 두 화가 그것을 갚는다.