►
Description
RustConf 2016 - Using Generics Effectively by Without Boats
Traits and type parameters are the core mechanism for abstraction in Rust. Other languages also have features like these, but few leverage them nearly as much as Rust does. This talk will describe the many powerful uses for Rust's generics system, how generics can be used as a replacement for tools like inheritance and duck typing, and how to leverage this system to write good, clean code.
A
Hello,
Mike's,
working
cool,
hey,
I,
guess
right
now,
I'm
without
boats
as
long
as
I'm
on
this
stage,
names
are
hard.
So
this
talk
is
about
rust
generic
system.
You
know
like
traits
and
tight
parameters,
and
it's
about
how
you
can
use
those
features
when
you're
writing
code
and
I've
been
a
rust
user
for
about
two
years
shortly
before
was
stabilized
and
I
have
a
couple
of
my
own
projects
and
rust.
A
Since
you
know
they
were
actual
physical
video
terminals,
not
virtual
terminals
being
emulated,
amish
on
a
machine,
and
so
not
the
implements
that
protocol,
but
also
a
new
protocol
to
support
other
features,
and
so
I'm
gonna
be
have
some
code.
Examples
in
this
talk
and
they're
all
going
to
be
coming
around
this
project,
so
I
wanted
to
give
you
that
context
about
what
these
examples
are
about.
But
so,
let's
talk
about
traits
traits
are
my
favorite
feature
of
rust?
I
considered
him
a
bigger
selling
for
to
the
language
than
even
you
know.
A
It's
awesome
like
memory
management
model
and
ownership
and
borrowing
and
things
like
that,
and
we've
been
using
crates
in
a
lot
of
really
cool
ways,
especially
in
you
know,
like
very
broad
libraries.
So
this
is
the
iterator
trait,
and
so,
if
you
wanted
to
find
a
new
iterator,
all
you
need
to
define
is
the
next
method
which
defines
how
to
get.
You
know
the
next
item
out
of
your
iterator
and
you
get
all
these
awesome
adapters
for
like
math
and
filter.
A
So
what
I
want
to
talk
about
is
about
how
we
use
traits
when
we're
you
know,
writing
our
application
code.
So
those
libraries
you
know
they're
going
to
be
used
in
a
whole
bunch
of
different
applications
with
a
lot
of
different
use
cases.
But
when
we
have,
you
know
some
specific
business
logic
that
we
want
to
implement,
you
know
how
can
we
use
traits
to
make
our
code
more
clean,
more
maintainable,
you
know
easier
to
read
and
refactor
and
such,
and
there
isn't
really
a
lot
of
good
guidance
for
this
and
it's
you
know.
A
My
projects
are
more
on
this
higher
level
of
implanting
a
particular
use
case
and
I've
been
grappling
with
it,
while
I've
been
building
my
different
projects,
especially
naughty
and
so
I,
was
preparing.
This
talk.
I
looked
at
some
other
applications
to
see
how
they
were
using
traits
and
compare
it
to
the
ways
that
I
was
using
traits
and
so
I
have
some
numbers
before
I
continue.
A
I
want
to
be
very
clear
that
I'm
going
to
be
highlighting
a
difference
between
my
application
and
applications
written
by
other
people
and
I
am
not
criticizing
the
way
that
those
other
applications
are
written.
I'm
not
only
saying
that,
because
their
authors
are
in
the
room
right
now,
I'm
also
saying
that,
because
I
think
it's
really
important
that
we
be
able
to
have
like
conversations
about
differences
in
the
way
that
we
code
without
it
being
like
this
sort
of
dogmatic
statement
of
oh.
A
A
So
my
project,
in
contrast,
I,
have
ninety
types
and
twelve
traits,
and
so
that
ratio
is,
you
know
closer
to
one
to
eight,
so
I'm
using
like
proportionally,
is
significantly
more
traits
than
other
people
are
using.
And
if
you
visualize
this,
you
know
you
can
see
that
you
know
the
bars
four
types
and
traits
in
cargo
and
rest
up
are,
you
know
pretty
proportional
and
then
for
naughty.
A
And
so
that's
you
know,
the
important
thing
about
polymorphism
is
that
you
have
one
interface
and
multiple
implementations,
and
so,
when
you
have
this
kind
of
like
branching
in
your
code,
where
you
want
to
jump
to
different
places
from
here,
you
can
use
a
trait
but
I
think
it's
a
lot
more
common
in
rust
to
use
an
enum
right.
So
it's
sort
of
intuitive
that
I
have
some
value
that
could
be
of
these
various
different
shapes
and
all
I
do
is
I.
A
A
So
whenever
you
write
something
to
that
grid,
it's
going
to
be
written
at
the
position
of
the
cursor
and
the
write
method.
Just
like
this
is
the
naive
implementation.
It
just
takes
a
char,
and
the
first
thing
it
does
is
it
assigns
that
char
to
the
cell
in
the
grid
underneath
the
current
cursor
and
then
because
you
don't
want
to
keep
assigning
to
the
same
cell
in
the
grid.
A
A
You
know,
someone
without
context
can
come
into
this
and
pretty
clearly
understand
what
it's
doing
and
how
it
and
how
it
could
possibly
change
the
grid,
but
it
has
a
really
fundamental
problem
and
that
problem
is
unicode,
and
so
as
anyone
who's
done,
string,
handling
and
rusts
knows.
Text
is
not
simple
when
it's
not
asking
right
like
there's
a
whole
bunch
of
different
edge
cases
and
all
the
different
kinds
of
human
languages,
and
so
here
are
some
specific
education
that
are
relevant
when
you're
implementing
a
terminal.
A
So
our
terminal
assumes
that
you
have
a
mono
space
Punk.
You
know
you
have
cells
that
are
forming
a
perfect
grid,
but
Unicode
specifies
that
some
characters
are
supposed
to
be
double
wide,
even
in
a
monospaced
font.
So
here
we
have,
you
know
some
Korean
characters
above
some
Latin
characters
and
Aladdin
characters.
A
Each
take
up
one
cell,
but
the
Korean
characters
take
up
two,
and
so
we
need
to
be
able
to
handle
that
in
the
state
of
the
grid
to
make
sure
we
don't
accidentally
have
characters
overriding
one
another
and
some
characters
aren't
actually
sposed
to
be
displayed
in
their
own
cell
at
all
right.
So
there's
like
modifying
and
extending
characters
which
are
code
points
that
are
just
to
be
applied
to
the
previous
character.
So
you
have
an
N
and
you
type
this
character
you're
supposed
to
get
an
N
you
out
of
it.
A
Instead
of
this
weird
and
followed
by
a
tilde
thing,
and
lastly,
I
said
the
naughty
you
know
supports
features
that
other
terminals
currently
don't
support,
and
so
one
feature
that
naughty
supports
is
writing
images
into
the
grid,
instead
of
only
writing
Unicode
characters,
and
so
you
know,
if
you
want
to
display
an
image
in
with
your
terminal
output,
it
could
be
really
difficult.
You
know
you
can't
really
do
it
in
the
cross-platform
way,
because
you
can't
and
like
the
windowing
system
is
all
these
different.
You
know,
wherever
your
cover
might
be
running
and
inaudi.
A
You
just
kind
of
write
an
image
and
we'll
be
in
line
with
the
text
output
of
your
program
and
so
sort
of
the
intuitive
solution.
To
solving
all
of
this
complexity,
it
was
just
to
define
an
enum
and
so
there's
the
char
data
enum,
and
it
has
a
variant
for
each
of
the
different
characters
or
not
feature.
They
feature
the
different
kinds
of
things
that
you
could
write,
which
could
be
characters
or
you
know
there
could
be
images
and
right
instead
of
taking
a
char,
takes
this
enum
and
then
the
first
thing
it
does.
A
Is
it
matches
over
that
data
and
you
know,
breaks
it
under
its
variants
and
then
each
variant
contains
the
algorithm
for
implementing
writing
that
particular
kind
of
data
into
the
grid,
and
here
under
the
char
variant,
we
have
the-
and
this
was
the
exact
same
code
as
the
original
method.
Only
now
it's
nested
way
deep
into
this
match,
and
it's
next
to
all
of
these
much
longer
and
more
complex
variants
for
all
of
the
different
other
kinds
of
data,
and
so
this
works.
But
it
has
some
problems
and
sort
of
the
most
obvious
problem.
A
Is
that
the
method
quickly
became
enormous
so
as
you're
dealing
with
all
the
edge
cases
when
you
have
like
you,
have
a
wide
character
but
you're
in
the
far
right
hand
of
the
grid,
and
so
you
need
to
you
know,
wrap
around
before
you
write
and
things
like
that.
You
know
you
have
this
like
multiple
like
it
was
in
three
digits
the
number
of
lines
in
this
method
and
there's
no
separation
from
the
logic
for
each
of
the
variants.
A
You
know
you
have
to
read
this
entire
method
and
there's
a
sort
of
more
subtle
but
related
problem,
which
is
that
there's
no
contract
defining
how
writing
each
of
these
variants
is
allowed
to
access
the
char
grid.
So
they
just
take
a
mutable
reference
to
the
entire
char
grid
and
there
could
be
like
other
fields
in
that
struck
and
you
don't
actually
know
how
they're
going
to
be
mutating
them
and
when
the
method
is
really
short,
that's
not
so
much
of
a
problem.
A
A
You
have
to
read
through
this
really
long
like
thicket
of
conditionals
to
figure
out
what's
happening,
and
so
I
did
some
exploratory
programming
and
ended
up
coming
up
with
this
refactor,
where
I
used
a
trait
instead
of
an
enum,
and
so
instead
of
having
the
char
data
enum,
there's
now
a
writer
creek,
which
defines
the
behavior
of
writing
something
into
a
char
grid,
and
so
it
takes
a
mutable
reference
to
the
two-dimensional
array,
the
underlying
grid
and
also
to
the
it
takes
the
cursor.
The
cursor
is
a
copy
types.
A
A
You
know
it
assigns
a
char
into
the
grid
at
the
cursor
position
and
then
moves
the
cursor
right
and
there's
also
an
implementation.
For
you
know,
each
of
the
other
variants
are
now
their
own
types
and
they
all
have
their
own
implementation,
and
so
somewhere
in
the
code,
you
get
each
of
these
variants.
A
We've
constructed
and
then
passed
and
are
good
calls
right
on
them
and
such
and
so
I
think
this
was
the
sort
of
a
straightforward
refactor
in
that
you
know,
I
just
hadn't
enum
that
had
become
too
long
and
so
I
converted
into
a
trait-
and
maybe
we
might
like,
differ
on
like
when
exactly
an
enum
is
too
complicated
and
it's
worth
the
trade.
And
you
know
there
are
some
performance
concerns
about
like.
Possibly
this
might
introduce
dynamic
dispatch.
A
In
this
case
it
didn't
introduce
any
dynamic
dispatch,
but
you
know
it
could,
but
something
I
think
that
I
do.
That
is
a
little
bit
more
uncommon.
Is
that
I
will
often
write
a
crate
when
I
only
have
one
implementation,
and
so
there's
nothing
really
polymorphic
about
that
right.
The
trade
is
only
going
to
be
implemented
by
one
type,
but
I'm
still
creating
this
generic.
That's
always
going
to
be
the
same
type
and
the
reason
I
do
that
is
that
the
other
aspect
of
traits
is
abstraction
and
so
I
have
another
quote.
A
This
is
from
the
introduction
to
computer
and
computation
of
programming
using
Python,
but,
as
you
can
tell
from
my
inability
to
read
the
title,
I
actually
just
found
it
on
Wikipedia.
Also,
the
essence
of
abstraction
is
preserving
information
that
is
relevant
in
a
given
context
and
forgetting
information
that
is
irrelevant
in
that
context
and
substraction,
is
you
know
about
determining
what
matters
for
implementing
this
particular
algorithm
and
only
presenting
that
information
and
hiding
the
other
information
and
so
I
think
it's
important
to
remember.
A
The
abstraction
is
not
only
about
code
reduced
right,
like
this
ideas,
sometimes
get
completed
when
we're
talking
about
abstraction,
but
a
code.
Reuse
is
an
advantage
of
writing
abstraction
right.
So
you
write
an
iterate,
you
have
the
iterator
crate
and
you
get
to
reuse
all
those
adapters.
But
the
real
reason
you
want
to
write
abstraction
is
separation
of
concerns.
So
you
want
to
isolate
your
components
from
each
other
and
only
present
do
we
present
them.
You
know
the
information
about
one
another.
A
A
But
the
terminal
is
not
giving
your
program
any
help
at
all,
and
so
you
can
see
here
in
this.
You
know
this
application,
there's
the
two
texts,
buffers
and
they're
sort
of
another
panel
between
them.
It's
like
a
gutter
and
then
there's
a
status
bar
below
them
and
such
and
so
Nadi
provides
a
feature
where
you
can
like
present
the
terminal,
an
abstract
description
of
how
it
should
be
dividing
up
the
screen,
and
then
it
will
create
separate
char
grids
that
fill
each
of
those
sections
of
the
screen.
A
So
it's
an
enum
where
one
variant
contains
a
char
grid
and
the
other
variant
contains
a
fork
between
a
Left
panel
and
a
right
panel
and
then
some
data
about
where
exactly
you
should
draw
the
split,
and
so
the
root
of
the
tree
is
going
to
be
the
whole
screen.
And
then
each
branch
is
each
section
down
to
the
leaf
nodes
which
contain
actual
grids.
And
importantly,
this
enum
only
is
coupled
to
char
grid
in
its
grid
variant.
The
split
variant
doesn't
care
anything
about
what
the
leaf
grids
act.
A
The
leaf
nodes
of
the
panel
actually
contain
and
I
wanted
them
to
be
as
decoupled
as
possible,
so
I
actually
defined
it
in
a
generic
way.
So
this
is
now
a
panel
of
T
and
the
grid
contains
any
type
T
and
I
constrained
that
type
T
by
a
trait
that
I
called
fill
panel,
and
so
this
is
a
panel
of
any
type
that
implements
the
behavior
of
filling
a
panel,
and
what
this
means
is
that
you
know
panel
can't
just
arbitrary.
A
We
call
any
method
it
wants
on
char
grid
if
I
want
to
call
a
method
on
char
grid
from
within
panel
I
have
to
think
about.
You
know:
is
this
appropriate
for
it
to
have
this
knowledge
of
char
grid?
You
know
I
have
to
it's
like
this
decision
point
where
I
have
to
think
about
whether
or
not
I'm
coupling
my
modules
too
closely
together
and
when
I
was
finished
implementing
panel.
It
actually
only
contained
two
items
in
the
fill
panel.
Crate
only
contain
two
items.
A
Panel
has
a
whole
bunch
of
methods,
and
the
first
is
a
constructor
that
just
takes
a
dimension
pair
and
the
second
is
resize,
which
takes.
You
know
it's
a
method
that
you
already
have
a
panel
and
you
want
to
resize
it
to
fit
into
a
new
section
of
the
screen,
and
so
both
of
these
methods
have
like
a
very
clear
connection
to
the
logic
and
panel
right.
A
That
I
had
to
find
a
really
good
abstraction
between
these
two
components
of
my
system,
but
there's
another
advantage
to
providing
these
traits,
and
so
I
said
that
it
only
had
one
implementation
and
that's
true
in
like
a
debug
build
or
a
release
build,
but
in
testing
build.
There
are
actually
multiple
implementations,
because
what
providing
a
trait
like
this
can
do
is
it
makes
it
much
easier
to
write
mocks.
A
A
But
if
your
code
is
generic,
you
can
just
create
a
new
type
which
implements
the
traits
that
are
required
and
then
pass
that
type
in
instead,
so
this
mock
grid
type,
it
isn't
a
real
grid.
It
just
contains
the
dimension
of
the
dimension
pair
of
a
width
and
a
height,
and
that
makes
it
you
know
so
it
only
cares
about.
It
only
contains
the
information
that
panel
cares
about,
and
not
any
of
that
no
irrelevant
information
about
having
a
grid
of
characters
and
writing
decorated
and
all
those
kinds
of
things.
A
And
so
then
my
test
I
just
had
to
you
know,
create
a
panel
that
can
heat
a
mock
grid
instead
of
been
hitting
a
char
grid,
and
then
it
you
know,
splits
it
or
whatever
operation
I
want
test
and
then
and
I,
just
a
search
that
the
grids
that
it
had
have
been
resized
to
be.
You
know
the
correct
dimensions
and
so
I
think
this
is
a
an
effective
way
of
writing.
Isolated
unit
tests
and
rust.
I
really
don't
know
a
better
way
to
mock.
A
A
So
how
will
you
know
that
you
know
you
should
use
a
technique
that
I
just
used
right
like?
How
do
you
know
when
an
enum
should
be
a
trait?
And
how
do
you
know
when
you
know
a
boundary
between
modules
that
you
want
to
keep
decoupled?
And
you
know
obviously
I
don't
actually
know
like
in
your
specific
use
case
when
you
should
do
that,
but
I
do
think.
I
know
how
we
can
find
the
answer
together
and
its
patterns.
A
This
is
a
really
good
book
by
the
way
it's
about
architecture
like
buildings
and
stuff,
but
you
should
totally
read
it
so
I
see
patterns
come
up
a
lot
a
few
times
in
rust
and
outside
of
rust
and
I.
Always
whatever
patterns
come
up.
Someone
always
said
something
like
this.
That
you
know
patterns
are
a
sign
that
your
language
isn't
powerful
enough.
You
know
you
just
need
a
better
type
system
or
you
need
macros
or
you
need
some
form
of
it's
passivity
that
your
language
just
doesn't
have,
and
I
really
think
that
this
is
wrong.
A
I
I,
don't
want
to
say
wrong
because
it's
not
oh
I,
think
it's
off.
The
mark.
I
think
that
it's
a
really
still
defied
way
of
looking
at
patterns
so
patterns,
don't
have
to
be
templates
for
classes
like
that's
the
really
common
way
that
you
know.
Parents
have
been
presented
as
being
like
abstract,
Factory
being
and
so
on,
but,
like
that's
a
really
still
divide
way
of
looking
at
what
a
pattern
is
a
pattern
is
a
way
of
recognizing
the
good
solution
to
the
problem
that
you
have
so
languages
can
just
on
their
own.
A
They
can
give
you
tools
for
creating
abstractions.
They
can
give
you
different
ways
of
expressing
yourself,
but
they
can't
give
you
the
insight
into
how
you
should
express
yourself
in
this
context.
They
can't
tell
you
you
know
what
the
right
way
to
solve
this
problem
is,
and
they
can
give
you
some
guidance,
but
really
what
we
need
is
like
community
consensus
around.
You
know
what
the
patterns
of
our
language
are
and
what's
idiomatic
and
what's
not
idiomatic
and
so
I
think
that
you
know
we
really
should
be
having
more
conversations
about
design
and
rust.
A
I
think
that,
as
you
know,
rust
gains
greater
adoption
and
we're
no
longer
implementing.
You
know
just
these
libraries
like
a
standard
library
or
serialization,
but
you
know
actual
application
code.
We
need
to
be
having
more
thoughtful
conversations
about
how
rust
ought
to
be
used,
and
you
know
try
to
come
to
some
consensus
about
what
the
idioms
of
the
language
are
about.
What
might
be
a
code
smell
about
what
patterns
you
can
use,
and
things
like
that,
and
you
know
we
have
some
movement
in
this
direction.
A
I
think
it's
Nick
Cameron
has
a
repo
about
patterns,
but
it's
you
know
most
entries
have
to
do
next
to
them
and
I
think
that
we
should
be
know
having
this
conversation
in
a
thoughtful
way
and
I
do
think
that
traits
are
a
really
good
way
of
finding
what
the
patterns
in
our
language
can
be.
I
think
that
you
know
playing
around
with
how
you
can
use
traits
to
a
better
abstract.
Your
problem
can
bring
out
a
lot
of
patterns.