`view_types`에 대해 일주일 동안 고민하며 생긴 생각들.
컴퓨터 과학 여정에 대한 몇 가지 생각.
view_types와 함께한 일주일2026-05-05에 게시됨
약 일주일 전부터 view_types(rust-lang/rust#155938) 작업을 시작했다. 처음에는 문법 측면에서 view_types가 어떤 모습이어야 하는지에 대해 강한 의견이 없었다. Lang Team이 무엇이 되어야 할지 논의하는 동안 view_types의 기본 지원을 추가하고, 그들이 합의에 도달할 때마다 내 구현을 업데이트하면 된다고 생각했다.
그런데 view_types에 대해 매일 한 시간 넘게 생각하는 것은 그 view_types에 대해 강한 의견을 형성하게 되는 좋은 방법이었다. 솔직히 말하면, 그건 예상했어야 했다.
이 글은 조금 덜 다듬어진 상태다. 지금 시점에서는 view_types에 대해 몇 시간이고 쓸 수 있을 것 같지만, 지금 내 초점은 지난 며칠 동안 생각했던 모든 것을 적어 두는 데 있다. 시간이 지나면서 내 관점(🥁)이 어떻게 바뀌는지 볼 수 있을지도 모르겠다.
View types for &T 처음에는 고려하지 않았던 점 하나는, 불변 대여와 가변 대여를 모두 표현하는 것이 유용할 수 있다는 것이다. 예를 들면:
struct Foo { bar: usize, baz: usize,}impl Foo { fn show_bar(&self.{ bar }) { println!("The value of baris{}", self.bar); }}fn main() { let mut foo = Foo { bar: 42, baz: 101 }; // Mutable borrow created *before* the function call let baz = &mut foo.baz; foo.show_bar(); // Mutable borrow used *after* the function call *baz += 1;}
이 예제에서는 Foo::show_bar를 호출하는 것이 완전히 괜찮다. 이 함수가 보기 위해 필요한 필드 집합 { bar }가 서로 겹치지 않기 때문이다.
심지어 &mut self.{ foo, mut bar } 같은 것도 허용할 수 있을 것이다. 이것은 “이 함수는 필드 foo를 불변으로 보고, 필드 bar를 가변으로 볼 수 있다”는 뜻이다. & 바로 뒤에 mut가 있어야 하는지는 잘 모르겠고, 그게 중요한지도 잘 모르겠다.
View types for T &T에 추가로 T에 대한 뷰를 지원하면, 부분적으로 초기화된 데이터를 함수에 전달할 수 있고, 상태를 추적하기 위해 제네릭 타입 매개변수가 필요 없는 타입 검사 가능한 빌더 패턴도 가능해진다:
struct Foo { bar: usize, baz: usize,}impl Foo { fn new() -> Foo.{} { Foo {} } fn with_bar(self.{ ..fields }, bar: usize) -> Foo.{ bar, ..fields } { Foo { bar, ..self } } fn with_baz(self.{ ..fields }, baz: usize) -> Foo.{ baz, ..fields } { Foo { baz, ..self } }}fn main() { let foo = Foo::new() // Foo.{} .with_bar(42) // Foo.{ bar } .with_baz(101); // Foo.{ bar, baz } (aka Foo)}
여기서 우리는 self의 볼 수 있을 가능성이 있는 필드들을 뷰 그룹 fields에 _바인딩_하고, 반환 타입에서 이 그룹을 사용한다. 이것이 Foo::with_bar의 반환 타입이, 반환값이 bar에서 볼 수 있으며 동시에 리시버와 동일한 필드들도 볼 수 있음을 나타내는 방식이다.
여기서 ..fields를 쓰는 이유는 이 개념이 실제로 구조체 업데이트 문법(r-expr.struct.update)과 가깝다고 느끼기 때문이다. 하지만 이 글의 초안에서는 패턴 타입과 어떻게 어울릴지 궁금해서 .{ fields @ .. }와 .{ ..fields }를 사용했었다. 결국 어떤 문법을 쓰게 될지는 나도 잘 모르겠고, 그게 중요한지도 잘 모르겠다.
서로 다른 라이프타임 이번 주 꽤 늦게 떠올랐던 점은, 사람들이 서로 다른 필드를 서로 다른 라이프타임으로 대여하고 싶어할 수도 있다는 것이다. 그런데 이 문법으로 그걸 표현할 방법이 나는 정말 보이지 않는다. 이걸 위한 문법을 직접 앉아서 생각해 내고 싶지는 않으니, 대신 이렇게 하겠다. 일단은 이 아이디어를 완전히 무시하고, 나보다 더 똑똑한 누군가가 나 대신 생각해 주기를 바라는 것이다 👍. 다만 대충이라도 그럴듯한 문법이 있다면, 그 문법으로 이것을 지원하도록 구현하는 건 기꺼이 하겠다.
문법이 정말로 못생겼나? 메모 초반에 적어 두었던 것 중 하나는 이거였다. “이 문법이 좀 덜 끔찍한 것으로 바뀌었으면 좋겠다.” 일주일이 지난 지금은 완전히 익숙해졌다. 오히려 괜찮다고까지 생각한다.
처음 let_else를 접했을 때도 정확히 같은 느낌이었던 것이 기억난다. 왜 누군가 이 괴상한 문법을 쓰려 할까? 나는 자꾸 이것을 if``else로 읽게 되는데? 나는 슬펐고 실망스러웠다. 몇 달 동안이나. 그러다 rustc의 attribute 리팩터링(rust-lang/rust#131229)에 관여하게 되었고, 매일 수십 개의 let_else를 읽기 시작했다. 이제는 let_else를 쓰지 않고는 못 배긴다. 어디에서나. 그리고 다른 언어에서 그걸 쓸 수 없으면 정말 아쉬워진다.
어쩌면 그냥 _나만의 문제_일지도 모르겠지만, 나는 .{ foo, bar }가 정말 괜찮다고 생각한다.