Rainer Stropek | @rstropek
Traits
Not Your Grandparents' Interfaces
Introduction
Rainer Stropek
- Passionate software developers for 25+ years
- Microsoft MVP, Regional Director
- Trainer, Teacher, Mentor
- 💕 community
Tic Tac Toe
Let's build a (slightly over-engineered 😜) TicTacToe game and learn about traits
on the way.
Sample code is available on GitHub
The Basics
Basics
pub trait Computer {
fn get_answer(&self) -> u8;
}
pub struct DeepThought;
impl Computer for DeepThought {
fn get_answer(&self) -> u8 {
42
}
}
fn main() {
let c = DeepThought {};
let _result = c.get_answer();
}
<playground::DeepThought as playground::Computer>::get_answer:
pushq %rax
movq %rdi, (%rsp)
movb $42, %al
popq %rcx
retq
playground::main:
pushq %rax
movq %rsp, %rdi
callq <playground::DeepThought as playground::Computer>::get_answer
movb %al, 7(%rsp)
popq %rax
retq
Basics
- Trait ToCompactString, implemented by BoardContent
-
SquareContent
- Enum implementing traits
- System traits Default, From/Into
-
BoardIndex
- System trait FromStr --> parse
- System trait Display --> println!
- System traits Add, Sub --> +/-
- How do we get Into "for free"?
Let's get more advanced
-
BoardContent
- Trait ToCompactString, implemented on top of another trait
- Iterators
- Make BoardContent iterable --> IntoIterator
- Error Types
- Implement Display trait for error type
- Indexer
- System traits Index, IndexMut --> []
Let's get more advanced
-
Game
- Build a game controller without dependency to BoardContent
- Build it on top of a trait (SquareAccessor --> Index --> Game)
What happens
behind the
scenes?
use std::io::*;
pub trait Animal {
fn make_sound(&self) -> &'static str;
}
pub struct Cat;
pub struct Dog;
impl Animal for Cat {
fn make_sound(&self) -> &'static str {
"Miau\n"
}
}
impl Animal for Dog {
fn make_sound(&self) -> &'static str {
"Wuff\n"
}
}
fn print_sound(animal: &impl Animal) {
stdout().write(animal.make_sound().as_bytes()).unwrap();
}
fn main() {
// Static dispatching
let a = Cat {};
print_sound(&a);
let a = Dog {};
print_sound(&a);
}
<playground::Cat as playground::Animal>::make_sound:
...
leaq .L__unnamed_4(%rip), %rax ; Miau
...
retq
<playground::Dog as playground::Animal>::make_sound:
...
leaq .L__unnamed_5(%rip), %rax ; Wuff
...
retq
playground::print_sound:
...
callq *std::io::stdio::stdout@GOTPCREL(%rip)
...
callq <playground::Dog as playground::Animal>::make_sound
...
callq *<std::io::stdio::Stdout as std::io::Write>::write@GOTPCREL(%rip)
...
retq
playground::print_sound:
...
callq *std::io::stdio::stdout@GOTPCREL(%rip)
...
callq <playground::Cat as playground::Animal>::make_sound
...
callq *<std::io::stdio::Stdout as std::io::Write>::write@GOTPCREL(%rip)
...
retq
playground::main:
subq $24, %rsp
leaq 8(%rsp), %rdi
callq playground::print_sound ; Cat
leaq 16(%rsp), %rdi
callq playground::print_sound ; Dog
addq $24, %rsp
retq
Direct function calls
Dynamic Dispatch
use std::io::*;
pub trait Animal {
fn make_sound(&self) -> &'static str;
}
pub struct Cat;
pub struct Dog;
impl Animal for Cat {
fn make_sound(&self) -> &'static str {
"Miau\n"
}
}
impl Animal for Dog {
fn make_sound(&self) -> &'static str {
"Wuff\n"
}
}
fn print_sound(animal: &dyn Animal) {
stdout().write(animal.make_sound().as_bytes()).unwrap();
}
fn main() {
let da: &dyn Animal = &Cat {};
print_sound(da);
let da: &dyn Animal = &Dog {};
print_sound(da);
}
playground::print_sound:
...
movq %rax, 80(%rsp)
movq 48(%rsp), %rax
movq 40(%rsp), %rdi
callq *24(%rax)
...
retq
playground::main:
...
leaq .L__unnamed_3(%rip), %rax
movq %rax, 16(%rsp)
leaq .L__unnamed_9(%rip), %rdi
leaq .L__unnamed_3(%rip), %rsi
callq playground::print_sound
...
leaq .L__unnamed_4(%rip), %rax
movq %rax, 32(%rsp)
leaq .L__unnamed_9(%rip), %rdi
leaq .L__unnamed_4(%rip), %rsi
callq playground::print_sound
addq $40, %rsp
retq
...
.L__unnamed_3:
.quad core::ptr::drop_in_place<playground::Cat>
.quad 0
.quad 1
.quad <playground::Cat as playground::Animal>::make_sound
.L__unnamed_4:
.quad core::ptr::drop_in_place<playground::Dog>
.quad 0
.quad 1
.quad <playground::Dog as playground::Animal>::make_sound
Indirect function call
Traits 🤘
Rainer Stropek | @rstropek
Traits - Not Your Grandparents' Interfaces
By Rainer Stropek
Traits - Not Your Grandparents' Interfaces
- 812