사실 나도 잘 모르겠는데 아는대로 설명해 보자면…
대표적인 예가 인터페이스의 메소드임. 가령 C#이나 Java의 경우 인터페이스든 클래스든 그 메소드가 동적바인딩이기 때문에 호출속도가 상대적으로 느림.
그에 비해서 Rust의 경우에는 동적바인딩이 아니라 컴파일시에 처리함.
인터페이스와 비슷한 역할을 하는 트레잇(Trait) 또한 메소드를 호출할 때 메소드를 찾아 호출하는 게 아니라
Trait형으로 변환될 때 객체의 주소와 Trait형에 정의된 메소드의 주소를 엮음.
그래서 trait형 레퍼런스의 크기는 32비트에서는 8바이트고 64바이트에서는 16바이트더라.
호출할 때 찾지 않고 매개변수로 넘길 때 찾으니 비용이 상대적으로 적거나 혹은 없음.
그래서 비용없는 추상화라고 부르는 것같음.
사실 Rust의 매력은 엄격한 메모리 규칙과 타입추론에 있으니까
그런 비용없는 추상화란 것에 매달릴 필요가 없음.
나도 궁금해서 잠깐 구글링했는데
https://ruudvanasseldonk.com/2016/11/30/zero-cost-abstractions
이런 글이 있었음.
이 코드는 버퍼와 coefficients배열에 있는 각 요소를 곱하고 더한 다음에 버퍼에 원래 있던 버퍼값과 넣는 코드임. 설명을 보면 이게 고수준 코드래.
근데 이걸 디코드하면
10c00:
movslq %r14d,%r11
movslq -0x2c(%r8,%rdi,4),%rsi
imul %r10,%rsi
movslq -0x30(%r8,%rdi,4),%r14
imul %rbp,%r14
add %rsi,%r14
movslq -0x28(%r8,%rdi,4),%rsi
imul %rdx,%rsi
add %rsi,%r14
movslq -0x24(%r8,%rdi,4),%rsi
imul %rax,%rsi
add %rsi,%r14
movslq -0x20(%r8,%rdi,4),%rsi
imul %rbx,%rsi
add %rsi,%r14
movslq -0x1c(%r8,%rdi,4),%rsi
imul %r15,%rsi
add %rsi,%r14
movslq -0x18(%r8,%rdi,4),%rsi
imul %r13,%rsi
add %rsi,%r14
movslq -0x14(%r8,%rdi,4),%rsi
imul %r12,%rsi
add %rsi,%r14
movslq -0x10(%r8,%rdi,4),%rsi
imul 0x8(%rsp),%rsi
add %rsi,%r14
movslq -0xc(%r8,%rdi,4),%rsi
imul 0x18(%rsp),%rsi
add %rsi,%r14
movslq -0x8(%r8,%rdi,4),%rsi
imul 0x20(%rsp),%rsi
add %rsi,%r14
imul 0x10(%rsp),%r11
add %r11,%r14
sar %cl,%r14
add (%r8,%rdi,4),%r14d
mov %r14d,(%r8,%rdi,4)
inc %rdi
cmp %r9,%rdi
jb 10c00 <claxon::subframe::predict_lpc::h6c02f07b190820c0+0x2b0>
로 변환되기 때문에 추상화를 위한 오버헤드가 전혀 없대(All overhead is gone completely)
뭔가 코드가 자바7 스트림 연상케 하네.. 아무튼 이런 고수준 코드를 추가 비용없이 사용할수 있다 이런건가 보네
ㄴ 체이닝하면서 zip하고 map하고 하는 거 보고 말하는 거라면, 꼭 자바의 스트림을 닮았다기보다는 함수형 스타일에서 쉽게 보이는 형태 같은데
루비랑 닮았네
비용 없큰 추상화 그거 C++ 애들이 만들어놓은 개념이랑 용어 그대로 갖다 쓴거 아녀 - return 0;