|
|
<!DOCTYPE HTML>
|
|
|
<html lang="en" class="sidebar-visible no-js rust">
|
|
|
<head>
|
|
|
<!-- Book generated using mdBook -->
|
|
|
<meta charset="UTF-8">
|
|
|
<title>Rust Design Patterns</title>
|
|
|
|
|
|
<meta name="robots" content="noindex" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Custom HTML head -->
|
|
|
|
|
|
|
|
|
|
|
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
|
|
<meta name="description" content="A catalogue of Rust design patterns, anti-patterns and idioms">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
<meta name="theme-color" content="#ffffff" />
|
|
|
|
|
|
|
|
|
<link rel="icon" href="favicon.svg">
|
|
|
|
|
|
|
|
|
<link rel="shortcut icon" href="favicon.png">
|
|
|
|
|
|
<link rel="stylesheet" href="css/variables.css">
|
|
|
<link rel="stylesheet" href="css/general.css">
|
|
|
<link rel="stylesheet" href="css/chrome.css">
|
|
|
|
|
|
<link rel="stylesheet" href="css/print.css" media="print">
|
|
|
|
|
|
|
|
|
<!-- Fonts -->
|
|
|
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
|
|
|
|
|
|
<link rel="stylesheet" href="fonts/fonts.css">
|
|
|
|
|
|
|
|
|
<!-- Highlight.js Stylesheets -->
|
|
|
<link rel="stylesheet" href="highlight.css">
|
|
|
<link rel="stylesheet" href="tomorrow-night.css">
|
|
|
<link rel="stylesheet" href="ayu-highlight.css">
|
|
|
|
|
|
<!-- Custom theme stylesheets -->
|
|
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
<body>
|
|
|
<!-- Provide site root to javascript -->
|
|
|
<script type="text/javascript">
|
|
|
var path_to_root = "";
|
|
|
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "rust";
|
|
|
</script>
|
|
|
|
|
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
|
<script type="text/javascript">
|
|
|
try {
|
|
|
var theme = localStorage.getItem('mdbook-theme');
|
|
|
var sidebar = localStorage.getItem('mdbook-sidebar');
|
|
|
|
|
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
|
}
|
|
|
|
|
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
|
}
|
|
|
} catch (e) { }
|
|
|
</script>
|
|
|
|
|
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
|
<script type="text/javascript">
|
|
|
var theme;
|
|
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
|
var html = document.querySelector('html');
|
|
|
html.classList.remove('no-js')
|
|
|
html.classList.remove('rust')
|
|
|
html.classList.add(theme);
|
|
|
html.classList.add('js');
|
|
|
</script>
|
|
|
|
|
|
<!-- Hide / unhide sidebar before it is displayed -->
|
|
|
<script type="text/javascript">
|
|
|
var html = document.querySelector('html');
|
|
|
var sidebar = 'hidden';
|
|
|
if (document.body.clientWidth >= 1080) {
|
|
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
|
sidebar = sidebar || 'visible';
|
|
|
}
|
|
|
html.classList.remove('sidebar-visible');
|
|
|
html.classList.add("sidebar-" + sidebar);
|
|
|
</script>
|
|
|
|
|
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
|
<div class="sidebar-scrollbox">
|
|
|
<ol class="chapter"><li class="chapter-item expanded "><a href="intro.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li class="chapter-item expanded "><a href="idioms/index.html"><strong aria-hidden="true">2.</strong> Idioms</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="idioms/coercion-arguments.html"><strong aria-hidden="true">2.1.</strong> Use borrowed types for arguments</a></li><li class="chapter-item expanded "><a href="idioms/concat-format.html"><strong aria-hidden="true">2.2.</strong> Concatenating Strings with format!</a></li><li class="chapter-item expanded "><a href="idioms/ctor.html"><strong aria-hidden="true">2.3.</strong> Constructor</a></li><li class="chapter-item expanded "><a href="idioms/default.html"><strong aria-hidden="true">2.4.</strong> The Default Trait</a></li><li class="chapter-item expanded "><a href="idioms/deref.html"><strong aria-hidden="true">2.5.</strong> Collections Are Smart Pointers</a></li><li class="chapter-item expanded "><a href="idioms/dtor-finally.html"><strong aria-hidden="true">2.6.</strong> Finalisation in Destructors</a></li><li class="chapter-item expanded "><a href="idioms/mem-replace.html"><strong aria-hidden="true">2.7.</strong> mem::{take(), replace()}</a></li><li class="chapter-item expanded "><a href="idioms/on-stack-dyn-dispatch.html"><strong aria-hidden="true">2.8.</strong> On-Stack Dynamic Dispatch</a></li><li class="chapter-item expanded "><a href="idioms/ffi-intro.html"><strong aria-hidden="true">2.9.</strong> Foreign function interface usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="idioms/ffi-errors.html"><strong aria-hidden="true">2.9.1.</strong> Idiomatic Errors</a></li><li class="chapter-item expanded "><a href="idioms/ffi-accepting-strings.html"><strong aria-hidden="true">2.9.2.</strong> Accepting Strings</a></li><li class="chapter-item expanded "><a href="idioms/ffi-passing-strings.html"><strong aria-hidden="true">2.9.3.</strong> Passing Strings</a></li></ol></li><li class="chapter-item expanded "><a href="idioms/option-iter.html"><strong aria-hidden="true">2.10.</strong> Iterating over an Option</a></li><li class="chapter-item expanded "><a href="idioms/pass-var-to-closure.html"><strong aria-hidden="true">2.11.</strong> Pass Variables to Closure</a></li><li class="chapter-item expanded "><a href="idioms/priv-extend.html"><strong aria-hidden="true">2.12.</strong> Privacy For Extensibility</a></li><li class="chapter-item expanded "><a href="idioms/rustdoc-init.html"><strong aria-hidden="true">2.13.</strong> Easy doc initialization</a></li><li class="chapter-item expanded "><a href="idioms/temporary-mutability.html"><strong aria-hidden="true">2.14.</strong> Temporary mutability</a></li></ol></li><li class="chapter-item expanded "><a href="patterns/index.html"><strong aria-hidden="true">3.</strong> Design Patterns</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="patterns/builder.html"><strong aria-hidden="true">3.1.</strong> Builder</a></li><li class="chapter-item expanded "><a href="patterns/compose-structs.html"><strong aria-hidden="true">3.2.</strong> Compose Structs</a></li><li class="chapter-item expanded "><a href="patterns/entry.html"><strong aria-hidden="true">3.3.</strong> Entry API</a></li><li class="chapter-item expanded "><a href="patterns/ffi-intro.html"><strong aria-hidden="true">3.4.</strong> Foreign function interface usage</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="patterns/ffi-export.html"><strong aria-hidden="true">3.4.1.</strong> Object-Based APIs</a></li><li class="chapter-item expanded "><a href="patterns/ffi-wrappers.html"><strong aria-hidden="true">3.4.2.</strong> Type Consolidation into Wrappers</a></li></ol></li><li class="chapter-item expanded "><a href="patterns/fold.html"><strong aria-hidden="true">3.5.</strong> Fold</a></li><li class="chapter-item expanded "><a href="patterns/interpreter.html"><strong aria-hidden="true">3.6.</strong> Interpreter</a></li><li class="chapter-item expanded "><a href="patterns/newtype.html"><strong aria-hidden="true">3.7.</strong> Newtype</a></li><li class="chapter-item expanded "><a href="patterns/RAII.html"><strong aria-hidden="true">3.8.</strong> RAII Guards</a></li><li class="chapter-item expanded "><a href="patterns/small-crates.html"><strong aria-hidden="true">3.9.</strong> Prefer Small Crates</a></li><li class="chapter-item expanded "><a href="patterns/strategy.html"><strong aria-hidden="true">3.10.</strong> Strategy</a></li><li class="chapter-item expanded "><a href="patterns/unsafe-mods.html"><strong aria-hidden="true">3.11.</strong> Contain unsafety in small modules</a></li><li class="chapter-item expanded "><a href="patterns/visitor.html"><strong aria-hidden="true">3.12.</strong> Visitor</a></li></ol></li><li class="chapter-item expanded "><a href="anti_patterns/index.html"><strong aria-hidden="true">4.</strong> Anti-patterns</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="anti_patterns/deny-warnings.html"><strong aria-hidden="true">4.1.</strong> #[deny(warnings)]</a></li><li class="chapter-item expanded "><a href="anti_patterns/deref.html"><strong aria-hidden="true">4.2.</strong> Deref Polymorphism</a></li></ol></li><li class="chapter-item expanded "><a href="functional/index.html"><strong aria-hidden="true">5.</strong> Functional Programming</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="functional/paradigms.html"><strong aria-hidden="true">5.1.</strong> Programming paradigms</a></li></ol></li><li class="chapter-item expanded "><a href="additional_resources/index.html"><strong aria-hidden="true">6.</strong> Additional Resources</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="additional_resources/design-principles.html"><strong aria-hidden="true">6.1.</strong> Design principles</a></li></ol></li></ol>
|
|
|
</div>
|
|
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
|
|
|
</nav>
|
|
|
|
|
|
<div id="page-wrapper" class="page-wrapper">
|
|
|
|
|
|
<div class="page">
|
|
|
|
|
|
<div id="menu-bar-hover-placeholder"></div>
|
|
|
<div id="menu-bar" class="menu-bar sticky bordered">
|
|
|
<div class="left-buttons">
|
|
|
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
|
<i class="fa fa-bars"></i>
|
|
|
</button>
|
|
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
|
<i class="fa fa-paint-brush"></i>
|
|
|
</button>
|
|
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
|
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust (default)</button></li>
|
|
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
|
</ul>
|
|
|
|
|
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
|
|
<i class="fa fa-search"></i>
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h1 class="menu-title">Rust Design Patterns</h1>
|
|
|
|
|
|
<div class="right-buttons">
|
|
|
|
|
|
<a href="print.html" title="Print this book" aria-label="Print this book">
|
|
|
<i id="print-button" class="fa fa-print"></i>
|
|
|
</a>
|
|
|
|
|
|
|
|
|
<a href="https://github.com/rust-unofficial/patterns" title="Git repository" aria-label="Git repository">
|
|
|
<i id="git-repository-button" class="fa fa-github"></i>
|
|
|
</a>
|
|
|
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
|
|
|
<div id="search-wrapper" class="hidden">
|
|
|
<form id="searchbar-outer" class="searchbar-outer">
|
|
|
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
|
</form>
|
|
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
|
<div id="searchresults-header" class="searchresults-header"></div>
|
|
|
<ul id="searchresults">
|
|
|
</ul>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
|
|
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
|
<script type="text/javascript">
|
|
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
<div id="content" class="content">
|
|
|
<main>
|
|
|
<h1><a class="header" href="#introduction" id="introduction">Introduction</a></h1>
|
|
|
<h2><a class="header" href="#participation" id="participation">Participation</a></h2>
|
|
|
<p>If you are interested in contributing to this book, check out the
|
|
|
<a href="https://github.com/rust-unofficial/patterns/blob/master/CONTRIBUTING.md">contribution guidelines</a>.</p>
|
|
|
<h2><a class="header" href="#design-patterns" id="design-patterns">Design patterns</a></h2>
|
|
|
<p>When developing programs, we have to solve many problems.
|
|
|
A program can be viewed as a solution to a problem.
|
|
|
It can also be viewed as a collection of solutions to many different problems.
|
|
|
All of these solutions work together to solve a bigger problem.</p>
|
|
|
<h2><a class="header" href="#design-patterns-in-rust" id="design-patterns-in-rust">Design patterns in Rust</a></h2>
|
|
|
<p>There are many problems that share the same form.
|
|
|
Due to the fact that Rust is not object-oriented design patterns vary with
|
|
|
respect to other object-oriented programming languages.
|
|
|
While the details are different, since they have the same form they can be
|
|
|
solved using the same fundamental methods:</p>
|
|
|
<ul>
|
|
|
<li><a href="./patterns/index.html">Design patterns</a> are methods to solve common problems
|
|
|
when writing software.</li>
|
|
|
<li><a href="./anti_patterns/index.html">Anti-patterns</a> are methods to solve these same
|
|
|
common problems. However, while design patterns give us benefits,
|
|
|
anti-patterns create more problems.</li>
|
|
|
<li><a href="./idioms/index.html">Idioms</a> are guidelines to follow when coding.
|
|
|
They are social norms of the community.
|
|
|
You can break them, but if you do you should have a good reason for it.</li>
|
|
|
</ul>
|
|
|
<p>TODO: Mention why Rust is a bit special - functional elements, type system,
|
|
|
borrow checker</p>
|
|
|
<h1><a class="header" href="#idioms" id="idioms">Idioms</a></h1>
|
|
|
<p><a href="https://en.wikipedia.org/wiki/Programming_idiom">Idioms</a> are commonly used
|
|
|
styles and patterns largely agreed upon by a community. They are guidelines.
|
|
|
Writing idiomatic code allows other developers to understand what is happening
|
|
|
because they are familiar with the form that it has.</p>
|
|
|
<p>The computer understands the machine code that is generated by the compiler.
|
|
|
The language is therefore mostly beneficial to the developer.
|
|
|
So, since we have this abstraction layer, why not put it to good use and make
|
|
|
it simple?</p>
|
|
|
<p>Remember the <a href="https://en.wikipedia.org/wiki/KISS_principle">KISS principle</a>:
|
|
|
"Keep It Simple, Stupid". It claims that "most systems work best if they are
|
|
|
kept simple rather than made complicated; therefore, simplicity should be a key
|
|
|
goal in design, and unnecessary complexity should be avoided".</p>
|
|
|
<blockquote>
|
|
|
<p>Code is there for humans, not computers, to understand.</p>
|
|
|
</blockquote>
|
|
|
<h1><a class="header" href="#use-borrowed-types-for-arguments" id="use-borrowed-types-for-arguments">Use borrowed types for arguments</a></h1>
|
|
|
<h2><a class="header" href="#description" id="description">Description</a></h2>
|
|
|
<p>Using a target of a deref coercion can increase the flexibility of your code
|
|
|
when you are deciding which argument type to use for a function argument.
|
|
|
In this way, the function will accept more input types.</p>
|
|
|
<p>This is not limited to slice-able or fat pointer types.
|
|
|
In fact you should always prefer using the <strong>borrowed type</strong> over
|
|
|
<strong>borrowing the owned type</strong>.
|
|
|
Such as <code>&str</code> over <code>&String</code>, <code>&[T]</code> over <code>&Vec<T></code>, or <code>&T</code> over <code>&Box<T></code>.</p>
|
|
|
<p>Using borrowed types you can avoid layers of indirection for those instances
|
|
|
where the owned type already provides a layer of indirection. For instance, a
|
|
|
<code>String</code> has a layer of indirection, so a <code>&String</code> will have two layers of
|
|
|
indrection. We can avoid this by using <code>&str</code> instead, and letting <code>&String</code>
|
|
|
coerce to a <code>&str</code> whenever the function is invoked.</p>
|
|
|
<h2><a class="header" href="#example" id="example">Example</a></h2>
|
|
|
<p>For this example, we will illustrate some differences for using <code>&String</code> as a
|
|
|
function argument versus using a <code>&str</code>, but the ideas apply as well to using
|
|
|
<code>&Vec<T></code> versus using a <code>&[T]</code> or using a <code>&T</code> versus a <code>&Box<T></code>.</p>
|
|
|
<p>Consider an example where we wish to determine if a word contains three
|
|
|
consecutive vowels. We don't need to own the string to determine this, so we
|
|
|
will take a reference.</p>
|
|
|
<p>The code might look something like this:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">fn three_vowels(word: &String) -> bool {
|
|
|
let mut vowel_count = 0;
|
|
|
for c in word.chars() {
|
|
|
match c {
|
|
|
'a' | 'e' | 'i' | 'o' | 'u' => {
|
|
|
vowel_count += 1;
|
|
|
if vowel_count >= 3 {
|
|
|
return true
|
|
|
}
|
|
|
}
|
|
|
_ => vowel_count = 0
|
|
|
}
|
|
|
}
|
|
|
false
|
|
|
}
|
|
|
|
|
|
fn main() {
|
|
|
let ferris = "Ferris".to_string();
|
|
|
let curious = "Curious".to_string();
|
|
|
println!("{}: {}", ferris, three_vowels(&ferris));
|
|
|
println!("{}: {}", curious, three_vowels(&curious));
|
|
|
|
|
|
// This works fine, but the following two lines would fail:
|
|
|
// println!("Ferris: {}", three_vowels("Ferris"));
|
|
|
// println!("Curious: {}", three_vowels("Curious"));
|
|
|
|
|
|
}
|
|
|
</code></pre></pre>
|
|
|
<p>This works fine because we are passing a <code>&String</code> type as a parameter.
|
|
|
If we comment in the last two lines this example fails because a <code>&str</code> type
|
|
|
will not coerce to a <code>&String</code> type. We can fix this by simply modifying the
|
|
|
type for our argument.</p>
|
|
|
<p>For instance, if we change our function declaration to:</p>
|
|
|
<pre><code class="language-rust ignore">fn three_vowels(word: &str) -> bool {
|
|
|
</code></pre>
|
|
|
<p>then both versions will compile and print the same output.</p>
|
|
|
<pre><code class="language-bash">Ferris: false
|
|
|
Curious: true
|
|
|
</code></pre>
|
|
|
<p>But wait, that's not all! There is more to this story.
|
|
|
It's likely that you may say to yourself: that doesn't matter, I will never be
|
|
|
using a <code>&'static str</code> as an input anyways (as we did when we used <code>"Ferris"</code>).
|
|
|
Even ignoring this special example, you may still find that using <code>&str</code> will
|
|
|
give you more flexibility than using a <code>&String</code>.</p>
|
|
|
<p>Let's now take an example where someone gives us a sentence, and we want to
|
|
|
determine if any of the words in the sentence has a word that contains three
|
|
|
consecutive vowels.
|
|
|
We probably should make use of the function we have already defined and simply
|
|
|
feed in each word from the sentence.</p>
|
|
|
<p>An example of this could look like this:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">fn three_vowels(word: &str) -> bool {
|
|
|
let mut vowel_count = 0;
|
|
|
for c in word.chars() {
|
|
|
match c {
|
|
|
'a' | 'e' | 'i' | 'o' | 'u' => {
|
|
|
vowel_count += 1;
|
|
|
if vowel_count >= 3 {
|
|
|
return true
|
|
|
}
|
|
|
}
|
|
|
_ => vowel_count = 0
|
|
|
}
|
|
|
}
|
|
|
false
|
|
|
}
|
|
|
|
|
|
fn main() {
|
|
|
let sentence_string =
|
|
|
"Once upon a time, there was a friendly curious crab named Ferris".to_string();
|
|
|
for word in sentence_string.split(' ') {
|
|
|
if three_vowels(word) {
|
|
|
println!("{} has three consecutive vowels!", word);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</code></pre></pre>
|
|
|
<p>Running this example using our function declared with an argument type <code>&str</code>
|
|
|
will yield</p>
|
|
|
<pre><code class="language-bash">curious has three consecutive vowels!
|
|
|
</code></pre>
|
|
|
<p>However, this example will not run when our function is declared with an
|
|
|
argument type <code>&String</code>. This is because string slices are a <code>&str</code> and not a
|
|
|
<code>&String</code> which would require an allocation to be converted to <code>&String</code> which
|
|
|
is not implicit, whereas converting from <code>String</code> to <code>&str</code> is cheap and implicit.</p>
|
|
|
<h2><a class="header" href="#see-also" id="see-also">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://doc.rust-lang.org/reference/type-coercions.html">Rust Language Reference on Type Coercions</a></li>
|
|
|
<li>For more discussion on how to handle <code>String</code> and <code>&str</code> see
|
|
|
<a href="https://web.archive.org/web/20201112023149/https://hermanradtke.com/2015/05/03/string-vs-str-in-rust-functions.html">this blog series (2015)</a>
|
|
|
by Herman J. Radtke III</li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#concatenating-strings-with-format" id="concatenating-strings-with-format">Concatenating strings with <code>format!</code></a></h1>
|
|
|
<h2><a class="header" href="#description-1" id="description-1">Description</a></h2>
|
|
|
<p>It is possible to build up strings using the <code>push</code> and <code>push_str</code> methods on a
|
|
|
mutable <code>String</code>, or using its <code>+</code> operator. However, it is often more
|
|
|
convenient to use <code>format!</code>, especially where there is a mix of literal and
|
|
|
non-literal strings.</p>
|
|
|
<h2><a class="header" href="#example-1" id="example-1">Example</a></h2>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>fn say_hello(name: &str) -> String {
|
|
|
// We could construct the result string manually.
|
|
|
// let mut result = "Hello ".to_owned();
|
|
|
// result.push_str(name);
|
|
|
// result.push('!');
|
|
|
// result
|
|
|
|
|
|
// But using format! is better.
|
|
|
format!("Hello {}!", name)
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2><a class="header" href="#advantages" id="advantages">Advantages</a></h2>
|
|
|
<p>Using <code>format!</code> is usually the most succinct and readable way to combine strings.</p>
|
|
|
<h2><a class="header" href="#disadvantages" id="disadvantages">Disadvantages</a></h2>
|
|
|
<p>It is usually not the most efficient way to combine strings - a series of <code>push</code>
|
|
|
operations on a mutable string is usually the most efficient (especially if the
|
|
|
string has been pre-allocated to the expected size).</p>
|
|
|
<h1><a class="header" href="#constructors" id="constructors">Constructors</a></h1>
|
|
|
<h2><a class="header" href="#description-2" id="description-2">Description</a></h2>
|
|
|
<p>Rust does not have constructors as a language construct. Instead, the
|
|
|
convention is to use a static <code>new</code> method to create an object.</p>
|
|
|
<h2><a class="header" href="#example-2" id="example-2">Example</a></h2>
|
|
|
<pre><code class="language-rust ignore">// A Rust vector, see liballoc/vec.rs
|
|
|
pub struct Vec<T> {
|
|
|
buf: RawVec<T>,
|
|
|
len: usize,
|
|
|
}
|
|
|
|
|
|
impl<T> Vec<T> {
|
|
|
// Constructs a new, empty `Vec<T>`.
|
|
|
// Note this is a static method - no self.
|
|
|
// This constructor doesn't take any arguments, but some might in order to
|
|
|
// properly initialise an object
|
|
|
pub fn new() -> Vec<T> {
|
|
|
// Create a new Vec with fields properly initialised.
|
|
|
Vec {
|
|
|
// Note that here we are calling RawVec's constructor.
|
|
|
buf: RawVec::new(),
|
|
|
len: 0,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#see-also-1" id="see-also-1">See also</a></h2>
|
|
|
<p>The <a href="idioms/../patterns/builder.html">builder pattern</a> for constructing objects where
|
|
|
there are multiple configurations.</p>
|
|
|
<h1><a class="header" href="#the-default-trait" id="the-default-trait">The <code>Default</code> Trait</a></h1>
|
|
|
<h2><a class="header" href="#description-3" id="description-3">Description</a></h2>
|
|
|
<p>Many types in Rust have a <a href="idioms/ctor.html">constructor</a>. However, this is <em>specific</em> to the
|
|
|
type; Rust cannot abstract over "everything that has a <code>new()</code> method". To
|
|
|
allow this, the <a href="https://doc.rust-lang.org/stable/std/default/trait.Default.html"><code>Default</code></a> trait was conceived, which can be used with
|
|
|
containers and other generic types (e.g. see <a href="https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_or_default"><code>Option::unwrap_or_default()</code></a>).
|
|
|
Notably, some containers already implement it where applicable.</p>
|
|
|
<p>Not only do one-element containers like <code>Cow</code>, <code>Box</code> or <code>Arc</code> implement
|
|
|
<code>Default</code> for contained <code>Default</code> types, one can automatically
|
|
|
<code>#[derive(Default)]</code> for structs whose fields all implement it, so the more
|
|
|
types implement <code>Default</code>, the more useful it becomes.</p>
|
|
|
<p>On the other hand, constructors can take multiple arguments, while the
|
|
|
<code>default()</code> method does not. There can even be multiple constructors with
|
|
|
different names, but there can only be one <code>Default</code> implementation per type.</p>
|
|
|
<h2><a class="header" href="#example-3" id="example-3">Example</a></h2>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">use std::{path::PathBuf, time::Duration};
|
|
|
|
|
|
// note that we can simply auto-derive Default here.
|
|
|
#[derive(Default, Debug)]
|
|
|
struct MyConfiguration {
|
|
|
// Option defaults to None
|
|
|
output: Option<PathBuf>,
|
|
|
// Vecs default to empty vector
|
|
|
search_path: Vec<PathBuf>,
|
|
|
// Duration defaults to zero time
|
|
|
timeout: Duration,
|
|
|
// bool defaults to false
|
|
|
check: bool,
|
|
|
}
|
|
|
|
|
|
impl MyConfiguration {
|
|
|
// add setters here
|
|
|
}
|
|
|
|
|
|
fn main() {
|
|
|
// construct a new instance with default values
|
|
|
let mut conf = MyConfiguration::default();
|
|
|
// do something with conf here
|
|
|
conf.check = true;
|
|
|
println!("conf = {:#?}", conf);
|
|
|
}
|
|
|
</code></pre></pre>
|
|
|
<h2><a class="header" href="#see-also-2" id="see-also-2">See also</a></h2>
|
|
|
<ul>
|
|
|
<li>The <a href="idioms/ctor.html">constructor</a> idiom is another way to generate instances that may or may
|
|
|
not be "default"</li>
|
|
|
<li>The <a href="https://doc.rust-lang.org/stable/std/default/trait.Default.html"><code>Default</code></a> documentation (scroll down for the list of implementors)</li>
|
|
|
<li><a href="https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_or_default"><code>Option::unwrap_or_default()</code></a></li>
|
|
|
<li><a href="https://crates.io/crates/derive-new/"><code>derive(new)</code></a></li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#collections-are-smart-pointers" id="collections-are-smart-pointers">Collections are smart pointers</a></h1>
|
|
|
<h2><a class="header" href="#description-4" id="description-4">Description</a></h2>
|
|
|
<p>Use the <code>Deref</code> trait to treat collections like smart pointers, offering owning
|
|
|
and borrowed views of data.</p>
|
|
|
<h2><a class="header" href="#example-4" id="example-4">Example</a></h2>
|
|
|
<pre><code class="language-rust ignore">use std::ops::Deref;
|
|
|
|
|
|
struct Vec<T> {
|
|
|
data: T,
|
|
|
//..
|
|
|
}
|
|
|
|
|
|
impl<T> Deref for Vec<T> {
|
|
|
type Target = [T];
|
|
|
|
|
|
fn deref(&self) -> &[T] {
|
|
|
//..
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>A <code>Vec<T></code> is an owning collection of <code>T</code>s, a slice (<code>&[T]</code>) is a borrowed
|
|
|
collection of <code>T</code>s. Implementing <code>Deref</code> for <code>Vec</code> allows implicit dereferencing
|
|
|
from <code>&Vec<T></code> to <code>&[T]</code> and includes the relationship in auto-derefencing
|
|
|
searches. Most methods you might expect to be implemented for <code>Vec</code>s are instead
|
|
|
implemented for slices.</p>
|
|
|
<p>See also <code>String</code> and <code>&str</code>.</p>
|
|
|
<h2><a class="header" href="#motivation" id="motivation">Motivation</a></h2>
|
|
|
<p>Ownership and borrowing are key aspects of the Rust language. Data structures
|
|
|
must account for these semantics properly in order to give a good user
|
|
|
experience. When implementing a data structure which owns its data, offering a
|
|
|
borrowed view of that data allows for more flexible APIs.</p>
|
|
|
<h2><a class="header" href="#advantages-1" id="advantages-1">Advantages</a></h2>
|
|
|
<p>Most methods can be implemented only for the borrowed view, they are then
|
|
|
implicitly available for the owning view.</p>
|
|
|
<p>Gives clients a choice between borrowing or taking ownership of data.</p>
|
|
|
<h2><a class="header" href="#disadvantages-1" id="disadvantages-1">Disadvantages</a></h2>
|
|
|
<p>Methods and traits only available via dereferencing are not taken into account
|
|
|
when bounds checking, so generic programming with data structures using this
|
|
|
pattern can get complex (see the <code>Borrow</code> and <code>AsRef</code> traits, etc.).</p>
|
|
|
<h2><a class="header" href="#discussion" id="discussion">Discussion</a></h2>
|
|
|
<p>Smart pointers and collections are analogous: a smart pointer points to a single
|
|
|
object, whereas a collection points to many objects. From the point of view of
|
|
|
the type system there is little difference between the two. A collection owns
|
|
|
its data if the only way to access each datum is via the collection and the
|
|
|
collection is responsible for deleting the data (even in cases of shared
|
|
|
ownership, some kind of borrowed view may be appropriate). If a collection owns
|
|
|
its data, it is usually useful to provide a view of the data as borrowed so that
|
|
|
it can be multiply referenced.</p>
|
|
|
<p>Most smart pointers (e.g., <code>Foo<T></code>) implement <code>Deref<Target=T></code>. However,
|
|
|
collections will usually dereference to a custom type. <code>[T]</code> and <code>str</code> have some
|
|
|
language support, but in the general case, this is not necessary. <code>Foo<T></code> can
|
|
|
implement <code>Deref<Target=Bar<T>></code> where <code>Bar</code> is a dynamically sized type and
|
|
|
<code>&Bar<T></code> is a borrowed view of the data in <code>Foo<T></code>.</p>
|
|
|
<p>Commonly, ordered collections will implement <code>Index</code> for <code>Range</code>s to provide
|
|
|
slicing syntax. The target will be the borrowed view.</p>
|
|
|
<h2><a class="header" href="#see-also-3" id="see-also-3">See also</a></h2>
|
|
|
<p><a href="idioms/../anti_patterns/deref.html">Deref polymorphism anti-pattern</a>.</p>
|
|
|
<p><a href="https://doc.rust-lang.org/std/ops/trait.Deref.html">Documentation for <code>Deref</code> trait</a>.</p>
|
|
|
<h1><a class="header" href="#finalisation-in-destructors" id="finalisation-in-destructors">Finalisation in destructors</a></h1>
|
|
|
<h2><a class="header" href="#description-5" id="description-5">Description</a></h2>
|
|
|
<p>Rust does not provide the equivalent to <code>finally</code> blocks - code that will be
|
|
|
executed no matter how a function is exited. Instead an object's destructor can
|
|
|
be used to run code that must be run before exit.</p>
|
|
|
<h2><a class="header" href="#example-5" id="example-5">Example</a></h2>
|
|
|
<pre><code class="language-rust ignore">fn bar() -> Result<(), ()> {
|
|
|
// These don't need to be defined inside the function.
|
|
|
struct Foo;
|
|
|
|
|
|
// Implement a destructor for Foo.
|
|
|
impl Drop for Foo {
|
|
|
fn drop(&mut self) {
|
|
|
println!("exit");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// The dtor of _exit will run however the function `bar` is exited.
|
|
|
let _exit = Foo;
|
|
|
// Implicit return with `?` operator.
|
|
|
baz()?;
|
|
|
// Normal return.
|
|
|
Ok(())
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#motivation-1" id="motivation-1">Motivation</a></h2>
|
|
|
<p>If a function has multiple return points, then executing code on exit becomes
|
|
|
difficult and repetitive (and thus bug-prone). This is especially the case where
|
|
|
return is implicit due to a macro. A common case is the <code>?</code> operator which
|
|
|
returns if the result is an <code>Err</code>, but continues if it is <code>Ok</code>. <code>?</code> is used as
|
|
|
an exception handling mechanism, but unlike Java (which has <code>finally</code>), there is
|
|
|
no way to schedule code to run in both the normal and exceptional cases.
|
|
|
Panicking will also exit a function early.</p>
|
|
|
<h2><a class="header" href="#advantages-2" id="advantages-2">Advantages</a></h2>
|
|
|
<p>Code in destructors will (nearly) always be run - copes with panics, early
|
|
|
returns, etc.</p>
|
|
|
<h2><a class="header" href="#disadvantages-2" id="disadvantages-2">Disadvantages</a></h2>
|
|
|
<p>It is not guaranteed that destructors will run. For example, if there is an
|
|
|
infinite loop in a function or if running a function crashes before exit.
|
|
|
Destructors are also not run in the case of a panic in an already panicking
|
|
|
thread. Therefore destructors cannot be relied on as finalisers where it is
|
|
|
absolutely essential that finalisation happens.</p>
|
|
|
<p>This pattern introduces some hard to notice, implicit code. Reading a function
|
|
|
gives no clear indication of destructors to be run on exit. This can make
|
|
|
debugging tricky.</p>
|
|
|
<p>Requiring an object and <code>Drop</code> impl just for finalisation is heavy on boilerplate.</p>
|
|
|
<h2><a class="header" href="#discussion-1" id="discussion-1">Discussion</a></h2>
|
|
|
<p>There is some subtlety about how exactly to store the object used as a
|
|
|
finaliser. It must be kept alive until the end of the function and must then be
|
|
|
destroyed. The object must always be a value or uniquely owned pointer (e.g.,
|
|
|
<code>Box<Foo></code>). If a shared pointer (such as <code>Rc</code>) is used, then the finaliser can
|
|
|
be kept alive beyond the lifetime of the function. For similar reasons, the
|
|
|
finaliser should not be moved or returned.</p>
|
|
|
<p>The finaliser must be assigned into a variable, otherwise it will be destroyed
|
|
|
immediately, rather than when it goes out of scope. The variable name must start
|
|
|
with <code>_</code> if the variable is only used as a finaliser, otherwise the compiler
|
|
|
will warn that the finaliser is never used. However, do not call the variable
|
|
|
<code>_</code> with no suffix - in that case it will be destroyed immediately.</p>
|
|
|
<p>In Rust, destructors are run when an object goes out of scope. This happens
|
|
|
whether we reach the end of block, there is an early return, or the program
|
|
|
panics. When panicking, Rust unwinds the stack running destructors for each
|
|
|
object in each stack frame. So, destructors get called even if the panic happens
|
|
|
in a function being called.</p>
|
|
|
<p>If a destructor panics while unwinding, there is no good action to take, so Rust
|
|
|
aborts the thread immediately, without running further destructors. This means
|
|
|
that destructors are not absolutely guaranteed to run. It also means that you
|
|
|
must take extra care in your destructors not to panic, since it could leave
|
|
|
resources in an unexpected state.</p>
|
|
|
<h2><a class="header" href="#see-also-4" id="see-also-4">See also</a></h2>
|
|
|
<p><a href="idioms/../patterns/RAII.html">RAII</a>.</p>
|
|
|
<h1><a class="header" href="#memtake_-replace_-to-keep-owned-values-in-changed-enums" id="memtake_-replace_-to-keep-owned-values-in-changed-enums"><code>mem::{take(_), replace(_)}</code> to keep owned values in changed enums</a></h1>
|
|
|
<h2><a class="header" href="#description-6" id="description-6">Description</a></h2>
|
|
|
<p>Say we have a <code>&mut MyEnum</code> which has (at least) two variants,
|
|
|
<code>A { name: String, x: u8 }</code> and <code>B { name: String }</code>. Now we want to change
|
|
|
<code>MyEnum::A</code> to a <code>B</code> if <code>x</code> is zero, while keeping <code>MyEnum::B</code> intact.</p>
|
|
|
<p>We can do this without cloning the <code>name</code>.</p>
|
|
|
<h2><a class="header" href="#example-6" id="example-6">Example</a></h2>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>use std::mem;
|
|
|
|
|
|
enum MyEnum {
|
|
|
A { name: String, x: u8 },
|
|
|
B { name: String }
|
|
|
}
|
|
|
|
|
|
fn a_to_b(e: &mut MyEnum) {
|
|
|
|
|
|
// we mutably borrow `e` here. This precludes us from changing it directly
|
|
|
// as in `*e = ...`, because the borrow checker won't allow it. Therefore
|
|
|
// the assignment to `e` must be outside the `if let` clause.
|
|
|
*e = if let MyEnum::A { ref mut name, x: 0 } = *e {
|
|
|
|
|
|
// this takes out our `name` and put in an empty String instead
|
|
|
// (note that empty strings don't allocate).
|
|
|
// Then, construct the new enum variant (which will
|
|
|
// be assigned to `*e`, because it is the result of the `if let` expression).
|
|
|
MyEnum::B { name: mem::take(name) }
|
|
|
|
|
|
// In all other cases, we return immediately, thus skipping the assignment
|
|
|
} else { return }
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>This also works with more variants:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>use std::mem;
|
|
|
|
|
|
enum MultiVariateEnum {
|
|
|
A { name: String },
|
|
|
B { name: String },
|
|
|
C,
|
|
|
D
|
|
|
}
|
|
|
|
|
|
fn swizzle(e: &mut MultiVariateEnum) {
|
|
|
use MultiVariateEnum::*;
|
|
|
*e = match *e {
|
|
|
// Ownership rules do not allow taking `name` by value, but we cannot
|
|
|
// take the value out of a mutable reference, unless we replace it:
|
|
|
A { ref mut name } => B { name: mem::take(name) },
|
|
|
B { ref mut name } => A { name: mem::take(name) },
|
|
|
C => D,
|
|
|
D => C
|
|
|
}
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2><a class="header" href="#motivation-2" id="motivation-2">Motivation</a></h2>
|
|
|
<p>When working with enums, we may want to change an enum value in place, perhaps
|
|
|
to another variant. This is usually done in two phases to keep the borrow
|
|
|
checker happy. In the first phase, we observe the existing value and look at
|
|
|
its parts to decide what to do next. In the second phase we may conditionally
|
|
|
change the value (as in the example above).</p>
|
|
|
<p>The borrow checker won't allow us to take out <code>name</code> of the enum (because
|
|
|
<em>something</em> must be there. We could of course <code>.clone()</code> name and put the clone
|
|
|
into our <code>MyEnum::B</code>, but that would be an instance of the [Clone to satisfy
|
|
|
the borrow checker] antipattern. Anyway, we can avoid the extra allocation by
|
|
|
changing <code>e</code> with only a mutable borrow.</p>
|
|
|
<p><code>mem::take</code> lets us swap out the value, replacing it with it's default value,
|
|
|
and returning the previous value. For <code>String</code>, the default value is an empty
|
|
|
<code>String</code>, which does not need to allocate. As a result, we get the original
|
|
|
<code>name</code> <em>as an owned value</em>. We can then wrap this in another enum.</p>
|
|
|
<p><strong>NOTE:</strong> <code>mem::replace</code> is very similar, but allows us to specify what to
|
|
|
replace the value with. An equivalent to our <code>mem::take</code> line would be
|
|
|
<code>mem::replace(name, String::new())</code>.</p>
|
|
|
<p>Note, however, that if we are using an <code>Option</code> and want to replace its
|
|
|
value with a <code>None</code>, <code>Option</code>’s <code>take()</code> method provides a shorter and
|
|
|
more idiomatic alternative.</p>
|
|
|
<h2><a class="header" href="#advantages-3" id="advantages-3">Advantages</a></h2>
|
|
|
<p>Look ma, no allocation! Also you may feel like Indiana Jones while doing it.</p>
|
|
|
<h2><a class="header" href="#disadvantages-3" id="disadvantages-3">Disadvantages</a></h2>
|
|
|
<p>This gets a bit wordy. Getting it wrong repeatedly will make you hate the
|
|
|
borrow checker. The compiler may fail to optimize away the double store,
|
|
|
resulting in reduced performance as opposed to what you'd do in unsafe
|
|
|
languages.</p>
|
|
|
<p>Furthermore, the type you are taking needs to implement the <a href="idioms/./default.html"><code>Default</code>
|
|
|
trait</a>. However, if the type you're working with doesn't
|
|
|
implement this, you can instead use <code>mem::replace</code>.</p>
|
|
|
<h2><a class="header" href="#discussion-2" id="discussion-2">Discussion</a></h2>
|
|
|
<p>This pattern is only of interest in Rust. In GC'd languages, you'd take the
|
|
|
reference to the value by default (and the GC would keep track of refs), and in
|
|
|
other low-level languages like C you'd simply alias the pointer and fix things
|
|
|
later.</p>
|
|
|
<p>However, in Rust, we have to do a little more work to do this. An owned value
|
|
|
may only have one owner, so to take it out, we need to put something back in –
|
|
|
like Indiana Jones, replacing the artifact with a bag of sand.</p>
|
|
|
<h2><a class="header" href="#see-also-5" id="see-also-5">See also</a></h2>
|
|
|
<p>This gets rid of the [Clone to satisfy the borrow checker] antipattern in a
|
|
|
specific case.</p>
|
|
|
<p>[Clone to satisfy the borrow checker](TODO: Hinges on PR #23)</p>
|
|
|
<h1><a class="header" href="#on-stack-dynamic-dispatch" id="on-stack-dynamic-dispatch">On-Stack Dynamic Dispatch</a></h1>
|
|
|
<h2><a class="header" href="#description-7" id="description-7">Description</a></h2>
|
|
|
<p>We can dynamically dispatch over multiple values, however, to do so, we need
|
|
|
to declare multiple variables to bind differently-typed objects. To extend the
|
|
|
lifetime as necessary, we can use deferred conditional initialization, as seen
|
|
|
below:</p>
|
|
|
<h2><a class="header" href="#example-7" id="example-7">Example</a></h2>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">use std::io;
|
|
|
use std::fs;
|
|
|
|
|
|
<span class="boring">fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
</span><span class="boring">let arg = "-";
|
|
|
</span>
|
|
|
// These must live longer than `readable`, and thus are declared first:
|
|
|
let (mut stdin_read, mut file_read);
|
|
|
|
|
|
// We need to ascribe the type to get dynamic dispatch.
|
|
|
let readable: &mut dyn io::Read = if arg == "-" {
|
|
|
stdin_read = io::stdin();
|
|
|
&mut stdin_read
|
|
|
} else {
|
|
|
file_read = fs::File::open(arg)?;
|
|
|
&mut file_read
|
|
|
};
|
|
|
|
|
|
// Read from `readable` here.
|
|
|
|
|
|
<span class="boring">Ok(())
|
|
|
</span><span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2><a class="header" href="#motivation-3" id="motivation-3">Motivation</a></h2>
|
|
|
<p>Rust monomorphises code by default. This means a copy of the code will be
|
|
|
generated for each type it is used with and optimized independently. While this
|
|
|
allows for very fast code on the hot path, it also bloats the code in places
|
|
|
where performance is not of the essence, thus costing compile time and cache
|
|
|
usage.</p>
|
|
|
<p>Luckily, Rust allows us to use dynamic dispatch, but we have to explicitly ask
|
|
|
for it.</p>
|
|
|
<h2><a class="header" href="#advantages-4" id="advantages-4">Advantages</a></h2>
|
|
|
<p>We do not need to allocate anything on the heap. Neither do we need to
|
|
|
initialize something we won't use later, nor do we need to monomorphize the
|
|
|
whole code that follows to work with both <code>File</code> or <code>Stdin</code>.</p>
|
|
|
<h2><a class="header" href="#disadvantages-4" id="disadvantages-4">Disadvantages</a></h2>
|
|
|
<p>The code needs more moving parts than the <code>Box</code>-based version:</p>
|
|
|
<pre><code class="language-rust ignore">// We still need to ascribe the type for dynamic dispatch.
|
|
|
let readable: Box<dyn io::Read> = if arg == "-" {
|
|
|
Box::new(io::stdin())
|
|
|
} else {
|
|
|
Box::new(fs::File::open(arg)?)
|
|
|
};
|
|
|
// Read from `readable` here.
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#discussion-3" id="discussion-3">Discussion</a></h2>
|
|
|
<p>Rust newcomers will usually learn that Rust requires all variables to be
|
|
|
initialized <em>before use</em>, so it's easy to overlook the fact that <em>unused</em>
|
|
|
variables may well be uninitialized. Rust works quite hard to ensure that this
|
|
|
works out fine and only the initialized values are dropped at the end of their
|
|
|
scope.</p>
|
|
|
<p>The example meets all the constraints Rust places on us:</p>
|
|
|
<ul>
|
|
|
<li>All variables are initialized before using (in this case borrowing) them</li>
|
|
|
<li>Each variable only holds values of a single type. In our example, <code>stdin</code> is
|
|
|
of type <code>Stdin</code>, <code>file</code> is of type <code>File</code> and <code>readable</code> is of type <code>&mut dyn Read</code></li>
|
|
|
<li>Each borrowed value outlives all the references borrowed from it</li>
|
|
|
</ul>
|
|
|
<h2><a class="header" href="#see-also-6" id="see-also-6">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="idioms/dtor-finally.html">Finalisation in destructors</a> and
|
|
|
<a href="idioms/../patterns/RAII.html">RAII guards</a> can benefit from tight control over lifetimes.</li>
|
|
|
<li>For conditionally filled <code>Option<&T></code>s of (mutable) references, one can
|
|
|
initialize an <code>Option<T></code> directly and use its <a href="https://doc.rust-lang.org/std/option/enum.Option.html#method.as_ref"><code>.as_ref()</code></a> method to get an
|
|
|
optional reference.</li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#ffi-idioms" id="ffi-idioms">FFI Idioms</a></h1>
|
|
|
<p>Writing FFI code is an entire course in itself.
|
|
|
However, there are several idioms here that can act as pointers, and avoid
|
|
|
traps for inexperienced users of <code>unsafe</code> Rust.</p>
|
|
|
<p>This section contains idioms that may be useful when doing FFI.</p>
|
|
|
<ol>
|
|
|
<li>
|
|
|
<p><a href="idioms/./ffi-errors.html">Idiomatic Errors</a> - Error handling with integer codes and
|
|
|
sentinel return values (such as <code>NULL</code> pointers)</p>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><a href="idioms/./ffi-accepting-strings.html">Accepting Strings</a> with minimal unsafe code</p>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><a href="idioms/./ffi-passing-strings.html">Passing Strings</a> to FFI functions</p>
|
|
|
</li>
|
|
|
</ol>
|
|
|
<h1><a class="header" href="#error-handling-in-ffi" id="error-handling-in-ffi">Error Handling in FFI</a></h1>
|
|
|
<h2><a class="header" href="#description-8" id="description-8">Description</a></h2>
|
|
|
<p>In foreign languages like C, errors are represented by return codes.
|
|
|
However, Rust's type system allows much more rich error information to be
|
|
|
captured a propogated through a full type.</p>
|
|
|
<p>This best practice shows different kinds of error codes, and how to expose them
|
|
|
in a usable way:</p>
|
|
|
<ol>
|
|
|
<li>Flat Enums should be converted to integers and returned as codes.</li>
|
|
|
<li>Structured Enums should be converted to an integer code with a string error
|
|
|
message for detail.</li>
|
|
|
<li>Custom Error Types should become "transparent", with a C representation.</li>
|
|
|
</ol>
|
|
|
<h2><a class="header" href="#code-example" id="code-example">Code Example</a></h2>
|
|
|
<h3><a class="header" href="#flat-enums" id="flat-enums">Flat Enums</a></h3>
|
|
|
<pre><code class="language-rust ignore">enum DatabaseError {
|
|
|
IsReadOnly = 1, // user attempted a write operation
|
|
|
IOError = 2, // user should read the C errno() for what it was
|
|
|
FileCorrupted = 3, // user should run a repair tool to recover it
|
|
|
}
|
|
|
|
|
|
impl From<DatabaseError> for libc::c_int {
|
|
|
fn from(e: DatabaseError) -> libc::c_int {
|
|
|
(e as i8).into()
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h3><a class="header" href="#structured-enums" id="structured-enums">Structured Enums</a></h3>
|
|
|
<pre><code class="language-rust ignore">pub mod errors {
|
|
|
enum DatabaseError {
|
|
|
IsReadOnly,
|
|
|
IOError(std::io::Error),
|
|
|
FileCorrupted(String), // message describing the issue
|
|
|
}
|
|
|
|
|
|
impl From<DatabaseError> for libc::c_int {
|
|
|
fn from(e: DatabaseError) -> libc::c_int {
|
|
|
match e {
|
|
|
DatabaseError::IsReadOnly => 1,
|
|
|
DatabaseError::IOError(_) => 2,
|
|
|
DatabaseError::FileCorrupted(_) => 3,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
pub mod c_api {
|
|
|
use super::errors::DatabaseError;
|
|
|
|
|
|
#[no_mangle]
|
|
|
pub extern "C" fn db_error_description(
|
|
|
e: *const DatabaseError
|
|
|
) -> *mut libc::c_char {
|
|
|
|
|
|
let error: &DatabaseError = unsafe {
|
|
|
// SAFETY: pointer lifetime is greater than the current stack frame
|
|
|
&*e
|
|
|
};
|
|
|
|
|
|
let error_str: String = match error {
|
|
|
DatabaseError::IsReadOnly => {
|
|
|
format!("cannot write to read-only database");
|
|
|
}
|
|
|
DatabaseError::IOError(e) => {
|
|
|
format!("I/O Error: {}", e);
|
|
|
}
|
|
|
DatabaseError::FileCorrupted(s) => {
|
|
|
format!("File corrupted, run repair: {}", &s);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
let c_error = unsafe {
|
|
|
// SAFETY: copying error_str to an allocated buffer with a NUL
|
|
|
// character at the end
|
|
|
let mut malloc: *mut u8 = libc::malloc(error_str.len() + 1) as *mut _;
|
|
|
|
|
|
if malloc.is_null() {
|
|
|
return std::ptr::null_mut();
|
|
|
}
|
|
|
|
|
|
let src = error_str.as_bytes().as_ptr();
|
|
|
|
|
|
std::ptr::copy_nonoverlapping(src, malloc, error_str.len());
|
|
|
|
|
|
std::ptr::write(malloc.add(error_str.len()), 0);
|
|
|
|
|
|
malloc as *mut libc::c_char
|
|
|
};
|
|
|
|
|
|
c_error
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h3><a class="header" href="#custom-error-types" id="custom-error-types">Custom Error Types</a></h3>
|
|
|
<pre><code class="language-rust ignore">struct ParseError {
|
|
|
expected: char,
|
|
|
line: u32,
|
|
|
ch: u16
|
|
|
}
|
|
|
|
|
|
impl ParseError { /* ... */ }
|
|
|
|
|
|
/* Create a second version which is exposed as a C structure */
|
|
|
#[repr(C)]
|
|
|
pub struct parse_error {
|
|
|
pub expected: libc::c_char,
|
|
|
pub line: u32,
|
|
|
pub ch: u16
|
|
|
}
|
|
|
|
|
|
impl From<ParseError> for parse_error {
|
|
|
fn from(e: ParseError) -> parse_error {
|
|
|
let ParseError { expected, line, ch } = e;
|
|
|
parse_error { expected, line, ch }
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#advantages-5" id="advantages-5">Advantages</a></h2>
|
|
|
<p>This ensures that the foreign language has clear access to error information
|
|
|
while not compromising the Rust code's API at all.</p>
|
|
|
<h2><a class="header" href="#disadvantages-5" id="disadvantages-5">Disadvantages</a></h2>
|
|
|
<p>It's a lot of typing, and some types may not be able to be converted easily
|
|
|
to C.</p>
|
|
|
<h1><a class="header" href="#accepting-strings" id="accepting-strings">Accepting Strings</a></h1>
|
|
|
<h2><a class="header" href="#description-9" id="description-9">Description</a></h2>
|
|
|
<p>When accepting strings via FFI through pointers, there are two principles that
|
|
|
should be followed:</p>
|
|
|
<ol>
|
|
|
<li>Keep foreign strings "borrowed", rather than copying them directly.</li>
|
|
|
<li>Minimize <code>unsafe</code> code during the conversion.</li>
|
|
|
</ol>
|
|
|
<h2><a class="header" href="#motivation-4" id="motivation-4">Motivation</a></h2>
|
|
|
<p>Rust has built-in support for C-style strings with its <code>CString</code> and <code>CStr</code>
|
|
|
types. However, there are different approaches one can take with strings that
|
|
|
are being accepted from a foreign caller of a Rust function.</p>
|
|
|
<p>The best practice is simple: use <code>CStr</code> in such a way as to minimize unsafe
|
|
|
code, and create a borrowed slice. If an owned String is needed, call
|
|
|
<code>to_string()</code> on the string slice.</p>
|
|
|
<h2><a class="header" href="#code-example-1" id="code-example-1">Code Example</a></h2>
|
|
|
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
|
|
|
|
|
// other module content
|
|
|
|
|
|
#[no_mangle]
|
|
|
pub extern "C" fn mylib_log(msg: *const libc::c_char, level: libc::c_int) {
|
|
|
let level: crate::LogLevel = match level { /* ... */ };
|
|
|
|
|
|
let msg_str: &str = unsafe {
|
|
|
// SAFETY: accessing raw pointers expected to live for the call,
|
|
|
// and creating a shared reference that does not outlive the current
|
|
|
// stack frame.
|
|
|
match std::ffi::CStr::from_ptr(msg).to_str() {
|
|
|
Ok(s) => s,
|
|
|
Err(e) => {
|
|
|
crate::log_error("FFI string conversion failed");
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
crate::log(msg_str, level);
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#advantages-6" id="advantages-6">Advantages</a></h2>
|
|
|
<p>The example is is written to ensure that:</p>
|
|
|
<ol>
|
|
|
<li>The <code>unsafe</code> block is as small as possible.</li>
|
|
|
<li>The pointer with an "untracked" lifetime becomes a "tracked" shared
|
|
|
reference</li>
|
|
|
</ol>
|
|
|
<p>Consider an alternative, where the string is actually copied:</p>
|
|
|
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
|
|
|
|
|
// other module content
|
|
|
|
|
|
pub extern "C" fn mylib_log(msg: *const libc::c_char, level: libc::c_int) {
|
|
|
// DO NOT USE THIS CODE.
|
|
|
// IT IS UGLY, VERBOSE, AND CONTAINS A SUBTLE BUG.
|
|
|
|
|
|
let level: crate::LogLevel = match level { /* ... */ };
|
|
|
|
|
|
let msg_len = unsafe { /* SAFETY: strlen is what it is, I guess? */
|
|
|
libc::strlen(msg)
|
|
|
};
|
|
|
|
|
|
let mut msg_data = Vec::with_capacity(msg_len + 1);
|
|
|
|
|
|
let msg_cstr: std::ffi::CString = unsafe {
|
|
|
// SAFETY: copying from a foreign pointer expected to live
|
|
|
// for the entire stack frame into owned memory
|
|
|
std::ptr::copy_nonoverlapping(msg, msg_data.as_mut(), msg_len);
|
|
|
|
|
|
msg_data.set_len(msg_len + 1);
|
|
|
|
|
|
std::ffi::CString::from_vec_with_nul(msg_data).unwrap()
|
|
|
}
|
|
|
|
|
|
let msg_str: String = unsafe {
|
|
|
match msg_cstr.into_string() {
|
|
|
Ok(s) => s,
|
|
|
Err(e) => {
|
|
|
crate::log_error("FFI string conversion failed");
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
crate::log(&msg_str, level);
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>This code in inferior to the original in two respects:</p>
|
|
|
<ol>
|
|
|
<li>There is much more <code>unsafe</code> code, and more importantly, more invariants it
|
|
|
must uphold.</li>
|
|
|
<li>Due to the extensive arithmetic required, there is a bug in this version
|
|
|
that cases Rust <code>undefined behaviour</code>.</li>
|
|
|
</ol>
|
|
|
<p>The bug here is a simple mistake in pointer arithmetic: the string was copied,
|
|
|
all <code>msg_len</code> bytes of it. However, the <code>NUL</code> terminator at the end was not.</p>
|
|
|
<p>The Vector then had its size <em>set</em> to the length of the <em>zero padded string</em> --
|
|
|
rather than <em>resized</em> to it, which could have added a zero at the end.
|
|
|
As a result, the last byte in the Vector is uninitialized memory.
|
|
|
When the <code>CString</code> is created at the bottom of the block, its read of the
|
|
|
Vector will cause <code>undefined behaviour</code>!</p>
|
|
|
<p>Like many such issues, this would be difficult issue to track down.
|
|
|
Sometimes it would panic because the string was not <code>UTF-8</code>, sometimes it would
|
|
|
put a weird character at the end of the string, sometimes it would just
|
|
|
completely crash.</p>
|
|
|
<h2><a class="header" href="#disadvantages-6" id="disadvantages-6">Disadvantages</a></h2>
|
|
|
<p>None?</p>
|
|
|
<h1><a class="header" href="#passing-strings" id="passing-strings">Passing Strings</a></h1>
|
|
|
<h2><a class="header" href="#description-10" id="description-10">Description</a></h2>
|
|
|
<p>When passing strings to FFI functions, there are four principles that should be
|
|
|
followed:</p>
|
|
|
<ol>
|
|
|
<li>Make the lifetime of owned strings as long as possible.</li>
|
|
|
<li>Minimize <code>unsafe</code> code during the conversion.</li>
|
|
|
<li>If the C code can modify the string data, use <code>Vec</code> instead of <code>CString</code>.</li>
|
|
|
<li>Unless the Foreign Function API requires it, the ownership of the string
|
|
|
should not transfer to the callee.</li>
|
|
|
</ol>
|
|
|
<h2><a class="header" href="#motivation-5" id="motivation-5">Motivation</a></h2>
|
|
|
<p>Rust has built-in support for C-style strings with its <code>CString</code> and <code>CStr</code>
|
|
|
types. However, there are different approaches one can take with strings that
|
|
|
are being sent to a foreign function call from a Rust function.</p>
|
|
|
<p>The best practice is simple: use <code>CString</code> in such a way as to minimize
|
|
|
<code>unsafe</code> code. However, a secondary caveat is that
|
|
|
<em>the object must live long enough</em>, meaning the lifetime should be maximized.
|
|
|
In addition, the documentation explains that "round-tripping" a <code>CString</code> after
|
|
|
modification is UB, so additional work is necessary in that case.</p>
|
|
|
<h2><a class="header" href="#code-example-2" id="code-example-2">Code Example</a></h2>
|
|
|
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
|
|
|
|
|
// other module content
|
|
|
|
|
|
extern "C" {
|
|
|
fn seterr(message: *const libc::c_char);
|
|
|
fn geterr(buffer: *mut libc::c_char, size: libc::c_int) -> libc::c_int;
|
|
|
}
|
|
|
|
|
|
fn report_error_to_ffi<S: Into<String>>(
|
|
|
err: S
|
|
|
) -> Result<(), std::ffi::NulError>{
|
|
|
let c_err = std::ffi::CString::new(err.into())?;
|
|
|
|
|
|
unsafe {
|
|
|
// SAFETY: calling an FFI whose documentation says the pointer is
|
|
|
// const, so no modificationshould occur
|
|
|
seterr(c_err.as_ptr());
|
|
|
}
|
|
|
|
|
|
Ok(())
|
|
|
// The lifetime of c_err continues until here
|
|
|
}
|
|
|
|
|
|
fn get_error_from_ffi() -> Result<String, std::ffi::IntoStringError> {
|
|
|
let mut buffer = vec![0u8; 1024];
|
|
|
unsafe {
|
|
|
// SAFETY: calling an FFI whose documentation implies
|
|
|
// that the input need only live as long as the call
|
|
|
let written: usize = geterr(buffer.as_mut_ptr(), 1023).into();
|
|
|
|
|
|
buffer.truncate(written + 1);
|
|
|
}
|
|
|
|
|
|
std::ffi::CString::new(buffer).unwrap().into_string()
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#advantages-7" id="advantages-7">Advantages</a></h2>
|
|
|
<p>The example is written in a way to ensure that:</p>
|
|
|
<ol>
|
|
|
<li>The <code>unsafe</code> block is as small as possible.</li>
|
|
|
<li>The <code>CString</code> lives long enough.</li>
|
|
|
<li>Errors with typecasts are always propagated when possible.</li>
|
|
|
</ol>
|
|
|
<p>A common mistake (so common it's in the documentation) is to not use the
|
|
|
variable in the first block:</p>
|
|
|
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
|
|
|
|
|
// other module content
|
|
|
|
|
|
fn report_error<S: Into<String>>(err: S) -> Result<(), std::ffi::NulError> {
|
|
|
unsafe {
|
|
|
// SAFETY: whoops, this contains a dangling pointer!
|
|
|
seterr(std::ffi::CString::new(err.into())?.as_ptr());
|
|
|
}
|
|
|
Ok(())
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>This code will result in a dangling pointer, because the lifetime of the
|
|
|
<code>CString</code> is not extended by the pointer creation, unlike if a reference were
|
|
|
created.</p>
|
|
|
<p>Another issue frequently raised is that the initialization of a 1k vector of
|
|
|
zeroes is "slow". However, recent versions of Rust actually optimize that
|
|
|
particular macro to a call to <code>zmalloc</code>, meaning it is as fast as the operating
|
|
|
system's ability to return zeroed memory (which is quite fast).</p>
|
|
|
<h2><a class="header" href="#disadvantages-7" id="disadvantages-7">Disadvantages</a></h2>
|
|
|
<p>None?</p>
|
|
|
<h1><a class="header" href="#iterating-over-an-option" id="iterating-over-an-option">Iterating over an <code>Option</code></a></h1>
|
|
|
<h2><a class="header" href="#description-11" id="description-11">Description</a></h2>
|
|
|
<p><code>Option</code> can be viewed as a container that contains either zero or one
|
|
|
elements. In particular, it implements the <code>IntoIterator</code> trait, and as such
|
|
|
can be used with generic code that needs such a type.</p>
|
|
|
<h2><a class="header" href="#examples" id="examples">Examples</a></h2>
|
|
|
<p>Since <code>Option</code> implements <code>IntoIterator</code>, it can be used as an argument to
|
|
|
<a href="https://doc.rust-lang.org/std/iter/trait.Extend.html#tymethod.extend"><code>.extend()</code></a>:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>let turing = Some("Turing");
|
|
|
let mut logicians = vec!["Curry", "Kleene", "Markov"];
|
|
|
|
|
|
logicians.extend(turing);
|
|
|
|
|
|
// equivalent to
|
|
|
if let Some(turing_inner) = turing {
|
|
|
logicians.push(turing_inner);
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>If you need to tack an <code>Option</code> to the end of an existing iterator, you can
|
|
|
pass it to <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.chain"><code>.chain()</code></a>:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>let turing = Some("Turing");
|
|
|
let logicians = vec!["Curry", "Kleene", "Markov"];
|
|
|
|
|
|
for logician in logicians.iter().chain(turing.iter()) {
|
|
|
println!("{} is a logician", logician);
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>Note that if the <code>Option</code> is always <code>Some</code>, then it is more idiomatic to use
|
|
|
<a href="https://doc.rust-lang.org/std/iter/fn.once.html"><code>std::iter::once</code></a> on the
|
|
|
element instead.</p>
|
|
|
<p>Also, since <code>Option</code> implements <code>IntoIterator</code>, it's possible to iterate over
|
|
|
it using a <code>for</code> loop. This is equivalent to matching it with <code>if let Some(..)</code>,
|
|
|
and in most cases you should prefer the latter.</p>
|
|
|
<h2><a class="header" href="#see-also-7" id="see-also-7">See also</a></h2>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<p><a href="https://doc.rust-lang.org/std/iter/fn.once.html"><code>std::iter::once</code></a> is an
|
|
|
iterator which yields exactly one element. It's a more readable alternative to
|
|
|
<code>Some(foo).into_iter()</code>.</p>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map"><code>Iterator::filter_map</code></a>
|
|
|
is a version of <a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map"><code>Iterator::flat_map</code></a>,
|
|
|
specialized to mapping functions which return <code>Option</code>.</p>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p>The <a href="https://crates.io/crates/ref_slice"><code>ref_slice</code></a> crate provides functions
|
|
|
for converting an <code>Option</code> to a zero- or one-element slice.</p>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><a href="https://doc.rust-lang.org/std/option/enum.Option.html">Documentation for <code>Option<T></code></a></p>
|
|
|
</li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#pass-variables-to-closure" id="pass-variables-to-closure">Pass variables to closure</a></h1>
|
|
|
<h2><a class="header" href="#description-12" id="description-12">Description</a></h2>
|
|
|
<p>By default, closures capture their environment by borrowing. Or you can use
|
|
|
<code>move</code>-closure to move whole environment. However, often you want to move just
|
|
|
some variables to closure, give it copy of some data, pass it by reference, or
|
|
|
perform some other transformation.</p>
|
|
|
<p>Use variable rebinding in separate scope for that.</p>
|
|
|
<h2><a class="header" href="#example-8" id="example-8">Example</a></h2>
|
|
|
<p>Use</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>use std::rc::Rc;
|
|
|
|
|
|
let num1 = Rc::new(1);
|
|
|
let num2 = Rc::new(2);
|
|
|
let num3 = Rc::new(3);
|
|
|
let closure = {
|
|
|
// `num1` is moved
|
|
|
let num2 = num2.clone(); // `num2` is cloned
|
|
|
let num3 = num3.as_ref(); // `num3` is borrowed
|
|
|
move || {
|
|
|
*num1 + *num2 + *num3;
|
|
|
}
|
|
|
};
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>instead of</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>use std::rc::Rc;
|
|
|
|
|
|
let num1 = Rc::new(1);
|
|
|
let num2 = Rc::new(2);
|
|
|
let num3 = Rc::new(3);
|
|
|
|
|
|
let num2_cloned = num2.clone();
|
|
|
let num3_borrowed = num3.as_ref();
|
|
|
let closure = move || {
|
|
|
*num1 + *num2_cloned + *num3_borrowed;
|
|
|
};
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2><a class="header" href="#advantages-8" id="advantages-8">Advantages</a></h2>
|
|
|
<p>Copied data are grouped together with closure definition, so their purpose is
|
|
|
more clear and they will be dropped immediately even if they are not consumed
|
|
|
by closure.</p>
|
|
|
<p>Closure uses same variable names as surrounding code whether data are copied or
|
|
|
moved.</p>
|
|
|
<h2><a class="header" href="#disadvantages-8" id="disadvantages-8">Disadvantages</a></h2>
|
|
|
<p>Additional indentation of closure body.</p>
|
|
|
<h1><a class="header" href="#privacy-for-extensibility" id="privacy-for-extensibility">Privacy for extensibility</a></h1>
|
|
|
<h2><a class="header" href="#description-13" id="description-13">Description</a></h2>
|
|
|
<p>Use a private field to ensure that a struct is extensible without breaking
|
|
|
stability guarantees.</p>
|
|
|
<h2><a class="header" href="#example-9" id="example-9">Example</a></h2>
|
|
|
<pre><code class="language-rust ignore">mod a {
|
|
|
// Public struct.
|
|
|
pub struct S {
|
|
|
pub foo: i32,
|
|
|
// Private field.
|
|
|
bar: i32,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fn main(s: a::S) {
|
|
|
// Because S::bar is private, it cannot be named here and we must use `..`
|
|
|
// in the pattern.
|
|
|
let a::S { foo: _, ..} = s;
|
|
|
}
|
|
|
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#discussion-4" id="discussion-4">Discussion</a></h2>
|
|
|
<p>Adding a field to a struct is a mostly backwards compatible change.
|
|
|
However, if a client uses a pattern to deconstruct a struct instance, they
|
|
|
might name all the fields in the struct and adding a new one would break that
|
|
|
pattern. The client could name some of the fields and use <code>..</code> in the pattern,
|
|
|
in which case adding another field is backwards compatible. Making at least one
|
|
|
of the struct's fields private forces clients to use the latter form of patterns,
|
|
|
ensuring that the struct is future-proof.</p>
|
|
|
<p>The downside of this approach is that you might need to add an otherwise unneeded
|
|
|
field to the struct. You can use the <code>()</code> type so that there is no runtime overhead
|
|
|
and prepend <code>_</code> to the field name to avoid the unused field warning.</p>
|
|
|
<p>If Rust allowed private variants of enums, we could use the same trick to make
|
|
|
adding a variant to an enum backwards compatible. The problem there is exhaustive
|
|
|
match expressions. A private variant would force clients to have a <code>_</code> wildcard
|
|
|
pattern. A common way to implement this instead is using the <a href="https://doc.rust-lang.org/reference/attributes/type_system.html"><code>#[non_exhaustive]</code></a>
|
|
|
attribute.</p>
|
|
|
<h1><a class="header" href="#easy-doc-initialization" id="easy-doc-initialization">Easy doc initialization</a></h1>
|
|
|
<h2><a class="header" href="#description-14" id="description-14">Description</a></h2>
|
|
|
<p>If a struct takes significant effort to initialize, when writing docs, it can be
|
|
|
quicker to wrap your example with a helper function which takes the struct as an
|
|
|
argument.</p>
|
|
|
<h2><a class="header" href="#motivation-6" id="motivation-6">Motivation</a></h2>
|
|
|
<p>Sometimes there is a struct with multiple or complicated parameters and several
|
|
|
methods. Each of these methods should have examples.</p>
|
|
|
<p>For example:</p>
|
|
|
<pre><code class="language-rust ignore">struct Connection {
|
|
|
name: String,
|
|
|
stream: TcpStream,
|
|
|
}
|
|
|
|
|
|
impl Connection {
|
|
|
/// Sends a request over the connection.
|
|
|
///
|
|
|
/// # Example
|
|
|
/// ```no_run
|
|
|
/// # // Boilerplate are required to get an example working.
|
|
|
/// # let stream = TcpStream::connect("127.0.0.1:34254");
|
|
|
/// # let connection = Connection { name: "foo".to_owned(), stream };
|
|
|
/// # let request = Request::new("RequestId", RequestType::Get, "payload");
|
|
|
/// let response = connection.send_request(request);
|
|
|
/// assert!(response.is_ok());
|
|
|
/// ```
|
|
|
fn send_request(&self, request: Request) -> Result<Status, SendErr> {
|
|
|
// ...
|
|
|
}
|
|
|
|
|
|
/// Oh no, all that boilerplate needs to be repeated here!
|
|
|
fn check_status(&self) -> Status {
|
|
|
// ...
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#example-10" id="example-10">Example</a></h2>
|
|
|
<p>Instead of typing all of this boiler plate to create an <code>Connection</code> and
|
|
|
<code>Request</code> it is easier to just create a wrapping helper function which takes
|
|
|
them as arguments:</p>
|
|
|
<pre><code class="language-rust ignore">struct Connection {
|
|
|
name: String,
|
|
|
stream: TcpStream,
|
|
|
}
|
|
|
|
|
|
impl Connection {
|
|
|
/// Sends a request over the connection.
|
|
|
///
|
|
|
/// # Example
|
|
|
/// ```
|
|
|
/// # fn call_send(connection: Connection, request: Request) {
|
|
|
/// let response = connection.send_request(request);
|
|
|
/// assert!(response.is_ok());
|
|
|
/// # }
|
|
|
/// ```
|
|
|
fn send_request(&self, request: Request) {
|
|
|
// ...
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p><strong>Note</strong> in the above example the line <code>assert!(response.is_ok());</code> will not
|
|
|
actually run while testing because it is inside of a function which is never
|
|
|
invoked.</p>
|
|
|
<h2><a class="header" href="#advantages-9" id="advantages-9">Advantages</a></h2>
|
|
|
<p>This is much more concise and avoids repetitive code in examples.</p>
|
|
|
<h2><a class="header" href="#disadvantages-9" id="disadvantages-9">Disadvantages</a></h2>
|
|
|
<p>As example is in a function, the code will not be tested. Though it still will
|
|
|
checked to make sure it compiles when running a <code>cargo test</code>. So this pattern is
|
|
|
most useful when need <code>no_run</code>. With this, you do not need to add <code>no_run</code>.</p>
|
|
|
<h2><a class="header" href="#discussion-5" id="discussion-5">Discussion</a></h2>
|
|
|
<p>If assertions are not required this pattern works well.</p>
|
|
|
<p>If they are, an alternative can be to create a public method to create a helper
|
|
|
instance which is annotated with <code>#[doc(hidden)]</code> (so that users won't see it).
|
|
|
Then this method can be called inside of rustdoc because it is part of the
|
|
|
crate's public API.</p>
|
|
|
<h1><a class="header" href="#temporary-mutability" id="temporary-mutability">Temporary mutability</a></h1>
|
|
|
<h2><a class="header" href="#description-15" id="description-15">Description</a></h2>
|
|
|
<p>Often it is necessary to prepare and process some data, but after that data are
|
|
|
only inspected and never modified. The intention can be made explicit by redefining
|
|
|
the mutable variable as immutable.</p>
|
|
|
<p>It can be done either by processing data within nested block or by redefining
|
|
|
variable.</p>
|
|
|
<h2><a class="header" href="#example-11" id="example-11">Example</a></h2>
|
|
|
<p>Say, vector must be sorted before usage.</p>
|
|
|
<p>Using nested block:</p>
|
|
|
<pre><code class="language-rust ignore">let data = {
|
|
|
let mut data = get_vec();
|
|
|
data.sort();
|
|
|
data
|
|
|
};
|
|
|
|
|
|
// Here `data` is immutable.
|
|
|
</code></pre>
|
|
|
<p>Using variable rebinding:</p>
|
|
|
<pre><code class="language-rust ignore">let mut data = get_vec();
|
|
|
data.sort();
|
|
|
let data = data;
|
|
|
|
|
|
// Here `data` is immutable.
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#advantages-10" id="advantages-10">Advantages</a></h2>
|
|
|
<p>Compiler ensures that you don't accidentally mutate data after some point.</p>
|
|
|
<h2><a class="header" href="#disadvantages-10" id="disadvantages-10">Disadvantages</a></h2>
|
|
|
<p>Nested block requires additional indentation of block body.
|
|
|
One more line to return data from block or redefine variable.</p>
|
|
|
<h1><a class="header" href="#design-patterns-1" id="design-patterns-1">Design Patterns</a></h1>
|
|
|
<p><a href="https://en.wikipedia.org/wiki/Software_design_pattern">Design patterns</a> are
|
|
|
"general reusable solutions to a commonly occurring problem within a given
|
|
|
context in software design". Design patterns are a great way to describe the
|
|
|
culture of a programming language. Design patterns are very language-specific -
|
|
|
what is a pattern in one language may be unnecessary in another due to a
|
|
|
language feature, or impossible to express due to a missing feature.</p>
|
|
|
<p>If overused, design patterns can add unnecessary complexity to programs.
|
|
|
However, they are a great way to share intermediate and advanced level knowledge
|
|
|
about a programming language.</p>
|
|
|
<h2><a class="header" href="#design-patterns-in-rust-1" id="design-patterns-in-rust-1">Design patterns in Rust</a></h2>
|
|
|
<p>Rust has many very unique features. These features give us great benefit by removing
|
|
|
whole classes of problems. Some of them are also patterns that are <em>unique</em> to Rust.</p>
|
|
|
<h2><a class="header" href="#yagni" id="yagni">YAGNI</a></h2>
|
|
|
<p>If you're not familiar with it, YAGNI is an acronym that stands for
|
|
|
<code>You Aren't Going to Need It</code>. It's an important software design principle to apply
|
|
|
as you write code.</p>
|
|
|
<blockquote>
|
|
|
<p>The best code I ever wrote was code I never wrote.</p>
|
|
|
</blockquote>
|
|
|
<p>If we apply YAGNI to design patterns, we see that the features of Rust allow us to
|
|
|
throw out many patterns. For instance, there is no need for the <a href="https://en.wikipedia.org/wiki/Strategy_pattern">strategy pattern</a>
|
|
|
in Rust because we can just use <a href="https://doc.rust-lang.org/book/traits.html">traits</a>.</p>
|
|
|
<p>TODO: Maybe include some code to illustrate the traits.</p>
|
|
|
<h1><a class="header" href="#builder" id="builder">Builder</a></h1>
|
|
|
<h2><a class="header" href="#description-16" id="description-16">Description</a></h2>
|
|
|
<p>Construct an object with calls to a builder helper.</p>
|
|
|
<h2><a class="header" href="#example-12" id="example-12">Example</a></h2>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>#[derive(Debug, PartialEq)]
|
|
|
pub struct Foo {
|
|
|
// Lots of complicated fields.
|
|
|
bar: String,
|
|
|
}
|
|
|
|
|
|
pub struct FooBuilder {
|
|
|
// Probably lots of optional fields.
|
|
|
bar: String,
|
|
|
}
|
|
|
|
|
|
impl FooBuilder {
|
|
|
pub fn new(/* ... */) -> FooBuilder {
|
|
|
// Set the minimally required fields of Foo.
|
|
|
FooBuilder {
|
|
|
bar: String::from("X"),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
pub fn name(mut self, bar: String) -> FooBuilder {
|
|
|
// Set the name on the builder itself, and return the builder by value.
|
|
|
self.bar = bar;
|
|
|
self
|
|
|
}
|
|
|
|
|
|
// If we can get away with not consuming the Builder here, that is an
|
|
|
// advantage. It means we can use the FooBuilder as a template for constructing
|
|
|
// many Foos.
|
|
|
pub fn build(self) -> Foo {
|
|
|
// Create a Foo from the FooBuilder, applying all settings in FooBuilder
|
|
|
// to Foo.
|
|
|
Foo { bar: self.bar }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn builder_test() {
|
|
|
let foo = Foo {
|
|
|
bar: String::from("Y"),
|
|
|
};
|
|
|
let foo_from_builder: Foo = FooBuilder::new().name(String::from("Y")).build();
|
|
|
assert_eq!(foo, foo_from_builder);
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2><a class="header" href="#motivation-7" id="motivation-7">Motivation</a></h2>
|
|
|
<p>Useful when you would otherwise require many different constructors or where
|
|
|
construction has side effects.</p>
|
|
|
<h2><a class="header" href="#advantages-11" id="advantages-11">Advantages</a></h2>
|
|
|
<p>Separates methods for building from other methods.</p>
|
|
|
<p>Prevents proliferation of constructors</p>
|
|
|
<p>Can be used for one-liner initialisation as well as more complex construction.</p>
|
|
|
<h2><a class="header" href="#disadvantages-11" id="disadvantages-11">Disadvantages</a></h2>
|
|
|
<p>More complex than creating a struct object directly, or a simple constructor
|
|
|
function.</p>
|
|
|
<h2><a class="header" href="#discussion-6" id="discussion-6">Discussion</a></h2>
|
|
|
<p>This pattern is seen more frequently in Rust (and for simpler objects) than in
|
|
|
many other languages because Rust lacks overloading. Since you can only have a
|
|
|
single method with a given name, having multiple constructors is less nice in
|
|
|
Rust than in C++, Java, or others.</p>
|
|
|
<p>This pattern is often used where the builder object is useful in its own right,
|
|
|
rather than being just a builder. For example, see
|
|
|
<a href="https://doc.rust-lang.org/std/process/struct.Command.html"><code>std::process::Command</code></a>
|
|
|
is a builder for <a href="https://doc.rust-lang.org/std/process/struct.Child.html"><code>Child</code></a>
|
|
|
(a process). In these cases, the <code>T</code> and <code>TBuilder</code> pattern
|
|
|
of naming is not used.</p>
|
|
|
<p>The example takes and returns the builder by value. It is often more ergonomic
|
|
|
(and more efficient) to take and return the builder as a mutable reference. The
|
|
|
borrow checker makes this work naturally. This approach has the advantage that
|
|
|
one can write code like</p>
|
|
|
<pre><code class="language-rust ignore">let mut fb = FooBuilder::new();
|
|
|
fb.a();
|
|
|
fb.b();
|
|
|
let f = fb.build();
|
|
|
</code></pre>
|
|
|
<p>as well as the <code>FooBuilder::new().a().b().build()</code> style.</p>
|
|
|
<h2><a class="header" href="#see-also-8" id="see-also-8">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://web.archive.org/web/20210104103100/https://doc.rust-lang.org/1.12.0/style/ownership/builders.html">Description in the style guide</a></li>
|
|
|
<li><a href="https://crates.io/crates/derive_builder">derive_builder</a>, a crate for automatically
|
|
|
implementing this pattern while avoiding the boilerplate.</li>
|
|
|
<li><a href="patterns/../idioms/ctor.html">Constructor pattern</a> for when construction is simpler.</li>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Builder_pattern">Builder pattern (wikipedia)</a></li>
|
|
|
<li><a href="https://web.archive.org/web/20210104103000/https://rust-lang.github.io/api-guidelines/type-safety.html#c-builder">Construction of complex values</a></li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#compose-structs-together-for-better-borrowing" id="compose-structs-together-for-better-borrowing">Compose structs together for better borrowing</a></h1>
|
|
|
<p>TODO - this is not a very snappy name</p>
|
|
|
<h2><a class="header" href="#description-17" id="description-17">Description</a></h2>
|
|
|
<p>Sometimes a large struct will cause issues with the borrow checker - although
|
|
|
fields can be borrowed independently, sometimes the whole struct ends up being
|
|
|
used at once, preventing other uses. A solution might be to decompose the struct
|
|
|
into several smaller structs. Then compose these together into the original
|
|
|
struct. Then each struct can be borrowed separately and have more flexible
|
|
|
behaviour.</p>
|
|
|
<p>This will often lead to a better design in other ways: applying this design
|
|
|
pattern often reveals smaller units of functionality.</p>
|
|
|
<h2><a class="header" href="#example-13" id="example-13">Example</a></h2>
|
|
|
<p>Here is a contrived example of where the borrow checker foils us in our plan to
|
|
|
use a struct:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>struct A {
|
|
|
f1: u32,
|
|
|
f2: u32,
|
|
|
f3: u32,
|
|
|
}
|
|
|
|
|
|
fn foo(a: &mut A) -> &u32 { &a.f2 }
|
|
|
fn bar(a: &mut A) -> u32 { a.f1 + a.f3 }
|
|
|
|
|
|
fn baz(a: &mut A) {
|
|
|
// The later usage of x causes a to be borrowed for the rest of the function.
|
|
|
let x = foo(a);
|
|
|
// Borrow checker error:
|
|
|
// let y = bar(a); // ~ ERROR: cannot borrow `*a` as mutable more than once
|
|
|
// at a time
|
|
|
println!("{}", x);
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>We can apply this design pattern and refactor <code>A</code> into two smaller structs, thus
|
|
|
solving the borrow checking issue:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>// A is now composed of two structs - B and C.
|
|
|
struct A {
|
|
|
b: B,
|
|
|
c: C,
|
|
|
}
|
|
|
struct B {
|
|
|
f2: u32,
|
|
|
}
|
|
|
struct C {
|
|
|
f1: u32,
|
|
|
f3: u32,
|
|
|
}
|
|
|
|
|
|
// These functions take a B or C, rather than A.
|
|
|
fn foo(b: &mut B) -> &u32 { &b.f2 }
|
|
|
fn bar(c: &mut C) -> u32 { c.f1 + c.f3 }
|
|
|
|
|
|
fn baz(a: &mut A) {
|
|
|
let x = foo(&mut a.b);
|
|
|
// Now it's OK!
|
|
|
let y = bar(&mut a.c);
|
|
|
println!("{}", x);
|
|
|
}
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2><a class="header" href="#motivation-8" id="motivation-8">Motivation</a></h2>
|
|
|
<p>TODO Why and where you should use the pattern</p>
|
|
|
<h2><a class="header" href="#advantages-12" id="advantages-12">Advantages</a></h2>
|
|
|
<p>Lets you work around limitations in the borrow checker.</p>
|
|
|
<p>Often produces a better design.</p>
|
|
|
<h2><a class="header" href="#disadvantages-12" id="disadvantages-12">Disadvantages</a></h2>
|
|
|
<p>Leads to more verbose code.</p>
|
|
|
<p>Sometimes, the smaller structs are not good abstractions, and so we end up with
|
|
|
a worse design. That is probably a 'code smell', indicating that the program
|
|
|
should be refactored in some way.</p>
|
|
|
<h2><a class="header" href="#discussion-7" id="discussion-7">Discussion</a></h2>
|
|
|
<p>This pattern is not required in languages that don't have a borrow checker, so
|
|
|
in that sense is unique to Rust. However, making smaller units of functionality
|
|
|
often leads to cleaner code: a widely acknowledged principle of software
|
|
|
engineering, independent of the language.</p>
|
|
|
<p>This pattern relies on Rust's borrow checker to be able to borrow fields
|
|
|
independently of each other. In the example, the borrow checker knows that <code>a.b</code>
|
|
|
and <code>a.c</code> are distinct and can be borrowed independently, it does not try to
|
|
|
borrow all of <code>a</code>, which would make this pattern useless.</p>
|
|
|
<h1><a class="header" href="#entry-api" id="entry-api">Entry API</a></h1>
|
|
|
<h2><a class="header" href="#description-18" id="description-18">Description</a></h2>
|
|
|
<p>A short, prose description of the pattern.</p>
|
|
|
<h2><a class="header" href="#example-14" id="example-14">Example</a></h2>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>// An example of the pattern in action, should be mostly code, commented
|
|
|
// liberally.
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2><a class="header" href="#motivation-9" id="motivation-9">Motivation</a></h2>
|
|
|
<p>Why and where you should use the pattern</p>
|
|
|
<h2><a class="header" href="#advantages-13" id="advantages-13">Advantages</a></h2>
|
|
|
<p>Good things about this pattern.</p>
|
|
|
<h2><a class="header" href="#disadvantages-13" id="disadvantages-13">Disadvantages</a></h2>
|
|
|
<p>Bad things about this pattern. Possible contraindications.</p>
|
|
|
<h2><a class="header" href="#discussion-8" id="discussion-8">Discussion</a></h2>
|
|
|
<p>TODO vs insert_or_update etc.</p>
|
|
|
<h2><a class="header" href="#see-also-9" id="see-also-9">See also</a></h2>
|
|
|
<p><a href="https://github.com/rust-lang/rfcs/blob/master/text/0216-collection-views.md">RFC</a>
|
|
|
<a href="https://github.com/rust-lang/rfcs/blob/8e2d3a3341da533f846f61f10335b72c9a9f4740/text/0921-entry_v3.md">RFC</a></p>
|
|
|
<p><a href="https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.entry">Hashmap::entry docs</a></p>
|
|
|
<h1><a class="header" href="#ffi-patterns" id="ffi-patterns">FFI Patterns</a></h1>
|
|
|
<p>Writing FFI code is an entire course in itself.
|
|
|
However, there are several idioms here that can act as pointers, and avoid traps
|
|
|
for inexperienced users of unsafe Rust.</p>
|
|
|
<p>This section contains design patterns that may be useful when doing FFI.</p>
|
|
|
<ol>
|
|
|
<li>
|
|
|
<p><a href="patterns/./ffi-export.html">Object-Based API</a> design that has good memory safety characteristics,
|
|
|
and a clean boundary of what is safe and what is unsafe</p>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><a href="patterns/./ffi-wrappers.html">Type Consolidation into Wrappers</a> - group multiple Rust types
|
|
|
together into an opaque "object"</p>
|
|
|
</li>
|
|
|
</ol>
|
|
|
<h1><a class="header" href="#object-based-apis" id="object-based-apis">Object-Based APIs</a></h1>
|
|
|
<h2><a class="header" href="#description-19" id="description-19">Description</a></h2>
|
|
|
<p>When designing APIs in Rust which are exposed to other languages, there are some
|
|
|
important design principles which are contrary to normal Rust API design:</p>
|
|
|
<ol>
|
|
|
<li>All Encapsulated types should be <em>owned</em> by Rust, <em>managed</em> by the user,
|
|
|
and <em>opaque</em>.</li>
|
|
|
<li>All Transactional data types should be <em>owned</em> by the user, and <em>transparent</em>.</li>
|
|
|
<li>All library behavior should be functions acting upon Encapsulated types.</li>
|
|
|
<li>All library behavior should be encapsulated into types not based on structure,
|
|
|
but <em>provenance/lifetime</em>.</li>
|
|
|
</ol>
|
|
|
<h2><a class="header" href="#motivation-10" id="motivation-10">Motivation</a></h2>
|
|
|
<p>Rust has built-in FFI support to other languages.
|
|
|
It does this by providing a way for crate authors to provide C-compatible APIs
|
|
|
through different ABIs (though that is unimportant to this practice).</p>
|
|
|
<p>Well-designed Rust FFI follows C API design principles, while compromising the
|
|
|
design in Rust as little as possible. There are three goals with any foreign API:</p>
|
|
|
<ol>
|
|
|
<li>Make it easy to use in the target language.</li>
|
|
|
<li>Avoid the API dictating internal unsafety on the Rust side as much as possible.</li>
|
|
|
<li>Keep the potential for memory unsafety and Rust <code>undefined behaviour</code> as small
|
|
|
as possible.</li>
|
|
|
</ol>
|
|
|
<p>Rust code must trust the memory safety of the foreign language beyond a certain
|
|
|
point. However, every bit of <code>unsafe</code> code on the Rust side is an opportunity for
|
|
|
bugs, or to exacerbate <code>undefined behaviour</code>.</p>
|
|
|
<p>For example, if a pointer provenance is wrong, that may be a segfault due to
|
|
|
invalid memory access. But if it is manipulated by unsafe code, it could become
|
|
|
full-blown heap corruption.</p>
|
|
|
<p>The Object-Based API design allows for writing shims that have good memory safety
|
|
|
characteristics, and a clean boundary of what is safe and what is <code>unsafe</code>.</p>
|
|
|
<h2><a class="header" href="#code-example-3" id="code-example-3">Code Example</a></h2>
|
|
|
<p>The POSIX standard defines the API to access an on-file database, known as <a href="https://web.archive.org/web/20210105035602/https://www.mankier.com/0p/ndbm.h">DBM</a>.
|
|
|
It is an excellent example of an "object-based" API.</p>
|
|
|
<p>Here is the definition in C, which hopefully should be easy to read for those
|
|
|
involved in FFI. The commentary below should help explaining it for those who
|
|
|
miss the subtleties.</p>
|
|
|
<pre><code class="language-C">struct DBM;
|
|
|
typedef struct { void *dptr, size_t dsize } datum;
|
|
|
|
|
|
int dbm_clearerr(DBM *);
|
|
|
void dbm_close(DBM *);
|
|
|
int dbm_delete(DBM *, datum);
|
|
|
int dbm_error(DBM *);
|
|
|
datum dbm_fetch(DBM *, datum);
|
|
|
datum dbm_firstkey(DBM *);
|
|
|
datum dbm_nextkey(DBM *);
|
|
|
DBM *dbm_open(const char *, int, mode_t);
|
|
|
int dbm_store(DBM *, datum, datum, int);
|
|
|
</code></pre>
|
|
|
<p>This API defines two types: <code>DBM</code> and <code>datum</code>.</p>
|
|
|
<p>The <code>DBM</code> type was called an "encapsulated" type above.
|
|
|
It is designed to contain internal state, and acts as an entry point for the
|
|
|
library's behavior.</p>
|
|
|
<p>It is completely opaque to the user, who cannot create a <code>DBM</code> themselves since
|
|
|
they don't know its size or layout. Instead, they must call <code>dbm_open</code>, and that
|
|
|
only gives them <em>a pointer to one</em>.</p>
|
|
|
<p>This means all <code>DBM</code>s are "owned" by the library in a Rust sense.
|
|
|
The internal state of unknown size is kept in memory controlled by the library,
|
|
|
not the user. The user can only manage its life cycle with <code>open</code> and <code>close</code>,
|
|
|
and perform operations on it with the other functions.</p>
|
|
|
<p>The <code>datum</code> type was called a "transactional" type above.
|
|
|
It is designed to facilitate the exchange of information between the library and
|
|
|
its user.</p>
|
|
|
<p>The database is designed to store "unstructured data", with no pre-defined length
|
|
|
or meaning. As a result, the <code>datum</code> is the C equivalent of a Rust slice: a bunch
|
|
|
of bytes, and a count of how many there are. The main difference is that there is
|
|
|
no type information, which is what <code>void</code> indicates.</p>
|
|
|
<p>Keep in mind that this header is written from the library's point of view.
|
|
|
The user likely has some type they are using, which has a known size.
|
|
|
But the library does not care, and by the rules of C casting, any type behind a
|
|
|
pointer can be cast to <code>void</code>.</p>
|
|
|
<p>As noted earlier, this type is <em>transparent</em> to the user. But also, this type is
|
|
|
<em>owned</em> by the user.
|
|
|
This has subtle ramifications, due to that pointer inside it.
|
|
|
The question is, who owns the memory that pointer points to?</p>
|
|
|
<p>The answer for best memory safety is, "the user".
|
|
|
But in cases such as retrieving a value, the user does not know how to allocate
|
|
|
it correctly (since they don't know how long the value is). In this case, the library
|
|
|
code is expected to use the heap that the user has access to -- such as the C library
|
|
|
<code>malloc</code> and <code>free</code> -- and then <em>transfer ownership</em> in the Rust sense.</p>
|
|
|
<p>This may all seem speculative, but this is what a pointer means in C.
|
|
|
It means the same thing as Rust: "user defined lifetime."
|
|
|
The user of the library needs to read the documentation in order to use it correctly.
|
|
|
That said, there are some decisions that have fewer or greater consequences if users
|
|
|
do it wrong. Minimizing those is what this best practice is about, and the key
|
|
|
is to <em>transfer ownership of everything that is transparent</em>.</p>
|
|
|
<h2><a class="header" href="#advantages-14" id="advantages-14">Advantages</a></h2>
|
|
|
<p>This minimizes the number of memory safety guarantees the user must uphold to a
|
|
|
relatively small number:</p>
|
|
|
<ol>
|
|
|
<li>Do not call any function with a pointer not returned by <code>dbm_open</code> (invalid
|
|
|
access or corruption).</li>
|
|
|
<li>Do not call any function on a pointer after close (use after free).</li>
|
|
|
<li>The <code>dptr</code> on any <code>datum</code> must be <code>NULL</code>, or point to a valid slice of memory
|
|
|
at the advertised length.</li>
|
|
|
</ol>
|
|
|
<p>In addition, it avoids a lot of pointer provenance issues.
|
|
|
To understand why, let us consider an alternative in some depth: key iteration.</p>
|
|
|
<p>Rust is well known for its iterators.
|
|
|
When implementing one, the programmer makes a separate type with a bounded lifetime
|
|
|
to its owner, and implements the <code>Iterator</code> trait.</p>
|
|
|
<p>Here is how iteration would be done in Rust for <code>DBM</code>:</p>
|
|
|
<pre><code class="language-rust ignore">struct Dbm { ... }
|
|
|
|
|
|
impl Dbm {
|
|
|
/* ... */
|
|
|
pub fn keys<'it>(&'it self) -> DbmKeysIter<'it> { ... }
|
|
|
/* ... */
|
|
|
}
|
|
|
|
|
|
struct DbmKeysIter<'it> {
|
|
|
owner: &'it Dbm,
|
|
|
}
|
|
|
|
|
|
impl<'it> Iterator for DbmKeysIter<'it> { ... }
|
|
|
</code></pre>
|
|
|
<p>This is clean, idiomatic, and safe. thanks to Rust's guarantees.
|
|
|
However, consider what a straightforward API translation would look like:</p>
|
|
|
<pre><code class="language-rust ignore">#[no_mangle]
|
|
|
pub extern "C" fn dbm_iter_new(owner: *const Dbm) -> *mut DbmKeysIter {
|
|
|
// THIS API IS A BAD IDEA! For real applications, use object-based design instead.
|
|
|
}
|
|
|
#[no_mangle]
|
|
|
pub extern "C" fn dbm_iter_next(
|
|
|
iter: *mut DbmKeysIter,
|
|
|
key_out: *const datum
|
|
|
) -> libc::c_int {
|
|
|
// THIS API IS A BAD IDEA! For real applications, use object-based design instead.
|
|
|
}
|
|
|
#[no_mangle]
|
|
|
pub extern "C" fn dbm_iter_del(*mut DbmKeysIter) {
|
|
|
// THIS API IS A BAD IDEA! For real applications, use object-based design instead.
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>This API loses a key piece of information: the lifetime of the iterator must not
|
|
|
exceed the lifetime of the <code>Dbm</code> object that owns it. A user of the library could
|
|
|
use it in a way which causes the iterator to outlive the data it is iterating on,
|
|
|
resulting in reading uninitialized memory.</p>
|
|
|
<p>This example written in C contains a bug that will be explained afterwards:</p>
|
|
|
<pre><code class="language-C">int count_key_sizes(DBM *db) {
|
|
|
// DO NOT USE THIS FUNCTION. IT HAS A SUBTLE BUT SERIOUS BUG!
|
|
|
datum key;
|
|
|
int len = 0;
|
|
|
|
|
|
if (!dbm_iter_new(db)) {
|
|
|
dbm_close(db);
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
int l;
|
|
|
while ((l = dbm_iter_next(owner, &key)) >= 0) { // an error is indicated by -1
|
|
|
free(key.dptr);
|
|
|
len += key.dsize;
|
|
|
if (l == 0) { // end of the iterator
|
|
|
dbm_close(owner);
|
|
|
}
|
|
|
}
|
|
|
if l >= 0 {
|
|
|
return -1;
|
|
|
} else {
|
|
|
return len;
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>This bug is a classic. Here's what happens when the iterator returns the
|
|
|
end-of-iteration marker:</p>
|
|
|
<ol>
|
|
|
<li>The loop condition sets <code>l</code> to zero, and enters the loop because <code>0 >= 0</code>.</li>
|
|
|
<li>The length is incremented, in this case by zero.</li>
|
|
|
<li>The if statement is true, so the database is closed. There should be a break
|
|
|
statement here.</li>
|
|
|
<li>The loop condition executes again, causing a <code>next</code> call on the closed object.</li>
|
|
|
</ol>
|
|
|
<p>The worst part about this bug?
|
|
|
If the Rust implementation was careful, this code will work most of the time!
|
|
|
If the memory for the <code>Dbm</code> object is not immediately reused, an internal check
|
|
|
will almost certainly fail, resulting in the iterator returning a <code>-1</code> indicating
|
|
|
an error. But occasionally, it will cause a segmentation fault, or even worse,
|
|
|
nonsensical memory corruption!</p>
|
|
|
<p>None of this can be avoided by Rust.
|
|
|
From its perspective, it put those objects on its heap, returned pointers to them,
|
|
|
and gave up control of their lifetimes. The C code simply must "play nice".</p>
|
|
|
<p>The programmer must read and understand the API documentation.
|
|
|
While some consider that par for the course in C, a good API design can mitigate
|
|
|
this risk. The POSIX API for <code>DBM</code> did this by <em>consolidating the ownership</em> of
|
|
|
the iterator with its parent:</p>
|
|
|
<pre><code class="language-C">datum dbm_firstkey(DBM *);
|
|
|
datum dbm_nextkey(DBM *);
|
|
|
</code></pre>
|
|
|
<p>Thus, all of the lifetimes were bound together, and such unsafety was prevented.</p>
|
|
|
<h2><a class="header" href="#disadvantages-14" id="disadvantages-14">Disadvantages</a></h2>
|
|
|
<p>However, this design choice also has a number of drawbacks, which should be
|
|
|
considered as well.</p>
|
|
|
<p>First, the API itself becomes less expressive.
|
|
|
With POSIX DBM, there is only one iterator per object, and every call changes
|
|
|
its state. This is much more restrictive than iterators in almost any language,
|
|
|
even though it is safe. Perhaps with other related objects, whose lifetimes are
|
|
|
less hierarchical, this limitation is more of a cost than the safety.</p>
|
|
|
<p>Second, depending on the relationships of the API's parts, significant design effort
|
|
|
may be involved. Many of the easier design points have other patterns associated
|
|
|
with them:</p>
|
|
|
<ul>
|
|
|
<li>
|
|
|
<p><a href="patterns/./ffi-wrappers.html">Wrapper Type Consolidation</a> groups multiple Rust types together
|
|
|
into an opaque "object"</p>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><a href="patterns/../idioms/ffi-errors.html">FFI Error Passing</a> explains error handling with integer
|
|
|
codes and sentinel return values (such as <code>NULL</code> pointers)</p>
|
|
|
</li>
|
|
|
<li>
|
|
|
<p><a href="patterns/../idioms/ffi-accepting-strings.html">Accepting Foreign Strings</a> allows accepting
|
|
|
strings with minimal unsafe code, and is easier to get right than
|
|
|
<a href="patterns/../idioms/ffi-passing-strings.html">Passing Strings to FFI</a></p>
|
|
|
</li>
|
|
|
</ul>
|
|
|
<p>However, not every API can be done this way.
|
|
|
It is up to the best judgement of the programmer as to who their audience is.</p>
|
|
|
<h1><a class="header" href="#type-consolidation-into-wrappers" id="type-consolidation-into-wrappers">Type Consolidation into Wrappers</a></h1>
|
|
|
<h2><a class="header" href="#description-20" id="description-20">Description</a></h2>
|
|
|
<p>This pattern is designed to allow gracefully handling multiple related types,
|
|
|
while minimizing the surface area for memory unsafety.</p>
|
|
|
<p>One of the cornerstones of Rust's aliasing rules is lifetimes.
|
|
|
This ensures that many patterns of access between types can be memory safe,
|
|
|
data race safety included.</p>
|
|
|
<p>However, when Rust types are exported to other languages, they are usually transformed
|
|
|
into pointers. In Rust, a pointer means "the user manages the lifetime of the pointee."
|
|
|
It is their responsibility to avoid memory unsafety.</p>
|
|
|
<p>Some level of trust in the user code is thus required, notably around use-after-free
|
|
|
which Rust can do nothing about. However, some API designs place higher burdens
|
|
|
than others on the code written in the other language.</p>
|
|
|
<p>The lowest risk API is the "consolidated wrapper", where all possible interactions
|
|
|
with an object are folded into a "wrapper type", while keeping the Rust API clean.</p>
|
|
|
<h2><a class="header" href="#code-example-4" id="code-example-4">Code Example</a></h2>
|
|
|
<p>To understand this, let us look at a classic example of an API to export: iteration
|
|
|
through a collection.</p>
|
|
|
<p>That API looks like this:</p>
|
|
|
<ol>
|
|
|
<li>The iterator is initialized with <code>first_key</code>.</li>
|
|
|
<li>Each call to <code>next_key</code> will advance the iterator.</li>
|
|
|
<li>Calls to <code>next_key</code> if the iterator is at the end will do nothing.</li>
|
|
|
<li>As noted above, the iterator is "wrapped into" the collection (unlike the native
|
|
|
Rust API).</li>
|
|
|
</ol>
|
|
|
<p>If the iterator implements <code>nth()</code> efficiently, then it is possible to make it
|
|
|
ephemeral to each function call:</p>
|
|
|
<pre><code class="language-rust ignore">struct MySetWrapper {
|
|
|
myset: MySet,
|
|
|
iter_next: usize,
|
|
|
}
|
|
|
|
|
|
impl MySetWrapper {
|
|
|
pub fn first_key(&mut self) -> Option<&Key> {
|
|
|
self.iter_next = 0;
|
|
|
self.next_key()
|
|
|
}
|
|
|
pub fn next_key(&mut self) -> Option<&Key> {
|
|
|
if let Some(next) = self.myset.keys().nth(self.iter_next) {
|
|
|
self.iter_next += 1;
|
|
|
Some(next)
|
|
|
} else {
|
|
|
None
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>As a result, the wrapper is simple and contains no <code>unsafe</code> code.</p>
|
|
|
<h2><a class="header" href="#advantages-15" id="advantages-15">Advantages</a></h2>
|
|
|
<p>This makes APIs safer to use, avoiding issues with lifetimes between types.
|
|
|
See <a href="patterns/./ffi-export.html">Object-Based APIs</a> for more on the advantages and pitfalls
|
|
|
this avoids.</p>
|
|
|
<h2><a class="header" href="#disadvantages-15" id="disadvantages-15">Disadvantages</a></h2>
|
|
|
<p>Often, wrapping types is quite difficult, and sometimes a Rust API compromise
|
|
|
would make things easier.</p>
|
|
|
<p>As an example, consider an iterator which does not efficiently implement <code>nth()</code>.
|
|
|
It would definitely be worth putting in special logic to make the object handle
|
|
|
iteration internally, or to support a different access pattern efficiently that
|
|
|
only the Foreign Function API will use.</p>
|
|
|
<h3><a class="header" href="#trying-to-wrap-iterators-and-failing" id="trying-to-wrap-iterators-and-failing">Trying to Wrap Iterators (and Failing)</a></h3>
|
|
|
<p>To wrap any type of iterator into the API correctly, the wrapper would need to
|
|
|
do what a C version of the code would do: erase the lifetime of the iterator,
|
|
|
and manage it manually.</p>
|
|
|
<p>Suffice it to say, this is <em>incredibly</em> difficult.</p>
|
|
|
<p>Here is an illustration of just <em>one</em> pitfall.</p>
|
|
|
<p>A first version of <code>MySetWrapper</code> would look like this:</p>
|
|
|
<pre><code class="language-rust ignore">struct MySetWrapper {
|
|
|
myset: MySet,
|
|
|
iter_next: usize,
|
|
|
// created from a transmuted Box<KeysIter + 'self>
|
|
|
iterator: Option<NonNull<KeysIter<'static>>>,
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>With <code>transmute</code> being used to extend a lifetime, and a pointer to hide it,
|
|
|
it's ugly already. But it gets even worse: <em>any other operation can cause
|
|
|
Rust <code>undefined behaviour</code></em>.</p>
|
|
|
<p>Consider that the <code>MySet</code> in the wrapper could be manipulated by other
|
|
|
functions during iteration, such as storing a new value to the key it was
|
|
|
iterating over. The API doesn't discourage this, and in fact some similar C
|
|
|
libraries expect it.</p>
|
|
|
<p>A simple implementation of <code>myset_store</code> would be:</p>
|
|
|
<pre><code class="language-rust ignore">pub mod unsafe_module {
|
|
|
|
|
|
// other module content
|
|
|
|
|
|
pub fn myset_store(
|
|
|
myset: *mut MySetWrapper,
|
|
|
key: datum,
|
|
|
value: datum) -> libc::c_int {
|
|
|
|
|
|
// DO NOT USE THIS CODE. IT IS UNSAFE TO DEMONSTRATE A PROLBEM.
|
|
|
|
|
|
let myset: &mut MySet = unsafe { // SAFETY: whoops, UB occurs in here!
|
|
|
&mut (*myset).myset
|
|
|
};
|
|
|
|
|
|
/* ...check and cast key and value data... */
|
|
|
|
|
|
match myset.store(casted_key, casted_value) {
|
|
|
Ok(_) => 0,
|
|
|
Err(e) => e.into()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>If the iterator exists when this function is called, we have violated one of Rust's
|
|
|
aliasing rules. According to Rust, the mutable reference in this block must have
|
|
|
<em>exclusive</em> access to the object. If the iterator simply exists, it's not exclusive,
|
|
|
so we have <code>undefined behaviour</code>! <sup class="footnote-reference"><a href="#1">1</a></sup></p>
|
|
|
<p>To avoid this, we must have a way of ensuring that mutable reference really is exclusive.
|
|
|
That basically means clearing out the iterator's shared reference while it exists,
|
|
|
and then reconstructing it. In most cases, that will still be less efficient than
|
|
|
the C version.</p>
|
|
|
<p>Some may ask: how can C do this more efficiently?
|
|
|
The answer is, it cheats. Rust's aliasing rules are the problem, and C simply ignores
|
|
|
them for its pointers. In exchange, it is common to see code that is declared
|
|
|
in the manual as "not thread safe" under some or all circumstances. In fact,
|
|
|
the <a href="https://manpages.debian.org/buster/manpages/attributes.7.en.html">GNU C library</a>
|
|
|
has an entire lexicon dedicated to concurrent behavior!</p>
|
|
|
<p>Rust would rather make everything memory safe all the time, for both safety and
|
|
|
optimizations that C code cannot attain. Being denied access to certain shortcuts
|
|
|
is the price Rust programmers need to pay.</p>
|
|
|
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
|
|
|
<p>For the C programmers out there scratching their heads, the iterator need
|
|
|
not be read <em>during</em> this code cause the UB. The exclusivity rule also enables
|
|
|
compiler optimizations which may cause inconsistent observations by the iterator's
|
|
|
shared reference (e.g. stack spills or reordering instructions for efficiency).
|
|
|
These observations may happen <em>any time after</em> the mutable reference is created.</p>
|
|
|
</div>
|
|
|
<h1><a class="header" href="#fold" id="fold">Fold</a></h1>
|
|
|
<h2><a class="header" href="#description-21" id="description-21">Description</a></h2>
|
|
|
<p>Run an algorithm over each item in a collection of data to create a new item,
|
|
|
thus creating a whole new collection.</p>
|
|
|
<p>The etymology here is unclear to me. The terms 'fold' and 'folder' are used
|
|
|
in the Rust compiler, although it appears to me to be more like a map than a
|
|
|
fold in the usual sense. See the discussion below for more details.</p>
|
|
|
<h2><a class="header" href="#example-15" id="example-15">Example</a></h2>
|
|
|
<pre><code class="language-rust ignore">// The data we will fold, a simple AST.
|
|
|
mod ast {
|
|
|
pub enum Stmt {
|
|
|
Expr(Box<Expr>),
|
|
|
Let(Box<Name>, Box<Expr>),
|
|
|
}
|
|
|
|
|
|
pub struct Name {
|
|
|
value: String,
|
|
|
}
|
|
|
|
|
|
pub enum Expr {
|
|
|
IntLit(i64),
|
|
|
Add(Box<Expr>, Box<Expr>),
|
|
|
Sub(Box<Expr>, Box<Expr>),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// The abstract folder
|
|
|
mod fold {
|
|
|
use ast::*;
|
|
|
|
|
|
pub trait Folder {
|
|
|
// A leaf node just returns the node itself. In some cases, we can do this
|
|
|
// to inner nodes too.
|
|
|
fn fold_name(&mut self, n: Box<Name>) -> Box<Name> { n }
|
|
|
// Create a new inner node by folding its children.
|
|
|
fn fold_stmt(&mut self, s: Box<Stmt>) -> Box<Stmt> {
|
|
|
match *s {
|
|
|
Stmt::Expr(e) => Box::new(Stmt::Expr(self.fold_expr(e))),
|
|
|
Stmt::Let(n, e) => Box::new(Stmt::Let(self.fold_name(n), self.fold_expr(e))),
|
|
|
}
|
|
|
}
|
|
|
fn fold_expr(&mut self, e: Box<Expr>) -> Box<Expr> { ... }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
use fold::*;
|
|
|
use ast::*;
|
|
|
|
|
|
// An example concrete implementation - renames every name to 'foo'.
|
|
|
struct Renamer;
|
|
|
impl Folder for Renamer {
|
|
|
fn fold_name(&mut self, n: Box<Name>) -> Box<Name> {
|
|
|
Box::new(Name { value: "foo".to_owned() })
|
|
|
}
|
|
|
// Use the default methods for the other nodes.
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>The result of running the <code>Renamer</code> on an AST is a new AST identical to the old
|
|
|
one, but with every name changed to <code>foo</code>. A real life folder might have some
|
|
|
state preserved between nodes in the struct itself.</p>
|
|
|
<p>A folder can also be defined to map one data structure to a different (but
|
|
|
usually similar) data structure. For example, we could fold an AST into a HIR
|
|
|
tree (HIR stands for high-level intermediate representation).</p>
|
|
|
<h2><a class="header" href="#motivation-11" id="motivation-11">Motivation</a></h2>
|
|
|
<p>It is common to want to map a data structure by performing some operation on
|
|
|
each node in the structure. For simple operations on simple data structures,
|
|
|
this can be done using <code>Iterator::map</code>. For more complex operations, perhaps
|
|
|
where earlier nodes can affect the operation on later nodes, or where iteration
|
|
|
over the data structure is non-trivial, using the fold pattern is more
|
|
|
appropriate.</p>
|
|
|
<p>Like the visitor pattern, the fold pattern allows us to separate traversal of a
|
|
|
data structure from the operations performed to each node.</p>
|
|
|
<h2><a class="header" href="#discussion-9" id="discussion-9">Discussion</a></h2>
|
|
|
<p>Mapping data structures in this fashion is common in functional languages. In OO
|
|
|
languages, it would be more common to mutate the data structure in place. The
|
|
|
'functional' approach is common in Rust, mostly due to the preference for
|
|
|
immutability. Using fresh data structures, rather than mutating old ones, makes
|
|
|
reasoning about the code easier in most circumstances.</p>
|
|
|
<p>The trade-off between efficiency and reusability can be tweaked by changing how
|
|
|
nodes are accepted by the <code>fold_*</code> methods.</p>
|
|
|
<p>In the above example we operate on <code>Box</code> pointers. Since these own their data
|
|
|
exclusively, the original copy of the data structure cannot be re-used. On the
|
|
|
other hand if a node is not changed, reusing it is very efficient.</p>
|
|
|
<p>If we were to operate on borrowed references, the original data structure can be
|
|
|
reused; however, a node must be cloned even if unchanged, which can be
|
|
|
expensive.</p>
|
|
|
<p>Using a reference counted pointer gives the best of both worlds - we can reuse
|
|
|
the original data structure and we don't need to clone unchanged nodes. However,
|
|
|
they are less ergonomic to use and mean that the data structures cannot be
|
|
|
mutable.</p>
|
|
|
<h2><a class="header" href="#see-also-10" id="see-also-10">See also</a></h2>
|
|
|
<p>Iterators have a <code>fold</code> method, however this folds a data structure into a
|
|
|
value, rather than into a new data structure. An iterator's <code>map</code> is more like
|
|
|
this fold pattern.</p>
|
|
|
<p>In other languages, fold is usually used in the sense of Rust's iterators,
|
|
|
rather than this pattern. Some functional languages have powerful constructs for
|
|
|
performing flexible maps over data structures.</p>
|
|
|
<p>The <a href="patterns/visitor.html">visitor</a> pattern is closely related to fold. They share the
|
|
|
concept of walking a data structure performing an operation on each node.
|
|
|
However, the visitor does not create a new data structure nor consume the old
|
|
|
one.</p>
|
|
|
<h1><a class="header" href="#interpreter" id="interpreter">Interpreter</a></h1>
|
|
|
<h2><a class="header" href="#description-22" id="description-22">Description</a></h2>
|
|
|
<p>If a problem occurs very often and requires long and repetitive steps to solve
|
|
|
it, then the problem instances might be expressed in a simple language and an
|
|
|
interpreter object could solve it by interpreting the sentences written in this
|
|
|
simple language.</p>
|
|
|
<p>Basically, for any kind of problems we define:</p>
|
|
|
<ul>
|
|
|
<li>a <a href="https://en.wikipedia.org/wiki/Domain-specific_language">domain specific language</a>,</li>
|
|
|
<li>a grammar for this language,</li>
|
|
|
<li>an interpreter that solves the problem instances.</li>
|
|
|
</ul>
|
|
|
<h2><a class="header" href="#motivation-12" id="motivation-12">Motivation</a></h2>
|
|
|
<p>Our goal is to translate simple mathematical expressions into postfix expressions
|
|
|
(or <a href="https://en.wikipedia.org/wiki/Reverse_Polish_notation">Reverse Polish notation</a>)
|
|
|
For simplicity, our expressions consist of ten digits <code>0</code>, ..., <code>9</code> and two
|
|
|
operations <code>+</code>, <code>-</code>. For example, the expression <code>2 + 4</code> is translated into
|
|
|
<code>2 4 +</code>.</p>
|
|
|
<h2><a class="header" href="#context-free-grammar-for-our-problem" id="context-free-grammar-for-our-problem">Context Free Grammar for our problem</a></h2>
|
|
|
<p>Our task is translate infix expressions into postfix ones. Let's define a context
|
|
|
free grammar for a set of infix expressions over <code>0</code>, ..., <code>9</code>, <code>+</code>, and <code>-</code>,
|
|
|
where:</p>
|
|
|
<ul>
|
|
|
<li>terminal symbols: <code>0</code>, ..., <code>9</code>, <code>+</code>, <code>-</code></li>
|
|
|
<li>non-terminal symbols: <code>exp</code>, <code>term</code></li>
|
|
|
<li>start symbol is <code>exp</code></li>
|
|
|
<li>and the following are production rules</li>
|
|
|
</ul>
|
|
|
<pre><code class="language-ignore">exp -> exp + term
|
|
|
exp -> exp - term
|
|
|
exp -> term
|
|
|
term -> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
|
|
|
</code></pre>
|
|
|
<p><strong>NOTE:</strong> This grammar should be further transformed depending on what we are going
|
|
|
to do with it. For example, we might need to remove left recursion. For more
|
|
|
details please see <a href="https://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools">Compilers: Principles,Techniques, and Tools
|
|
|
</a>
|
|
|
(aka Dragon Book).</p>
|
|
|
<h2><a class="header" href="#solution" id="solution">Solution</a></h2>
|
|
|
<p>We simply implement a recursive descent parser. For simplicity's sake, the code
|
|
|
panics when an expression is syntactically wrong (for example <code>2-34</code> or <code>2+5-</code>
|
|
|
are wrong according to the grammar definition).</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">pub struct Interpreter<'a> {
|
|
|
it: std::str::Chars<'a>,
|
|
|
}
|
|
|
|
|
|
impl<'a> Interpreter<'a> {
|
|
|
|
|
|
pub fn new(infix: &'a str) -> Self {
|
|
|
Self { it: infix.chars() }
|
|
|
}
|
|
|
|
|
|
fn next_char(&mut self) -> Option<char> {
|
|
|
self.it.next()
|
|
|
}
|
|
|
|
|
|
pub fn interpret(&mut self, out: &mut String) {
|
|
|
self.term(out);
|
|
|
|
|
|
while let Some(op) = self.next_char() {
|
|
|
if op == '+' || op == '-' {
|
|
|
self.term(out);
|
|
|
out.push(op);
|
|
|
} else {
|
|
|
panic!("Unexpected symbol '{}'", op);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fn term(&mut self, out: &mut String) {
|
|
|
match self.next_char() {
|
|
|
Some(ch) if ch.is_digit(10) => out.push(ch),
|
|
|
Some(ch) => panic!("Unexpected symbol '{}'", ch),
|
|
|
None => panic!("Unexpected end of string"),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
pub fn main() {
|
|
|
let mut intr = Interpreter::new("2+3");
|
|
|
let mut postfix = String::new();
|
|
|
intr.interpret(&mut postfix);
|
|
|
assert_eq!(postfix, "23+");
|
|
|
|
|
|
intr = Interpreter::new("1-2+3-4");
|
|
|
postfix.clear();
|
|
|
intr.interpret(&mut postfix);
|
|
|
assert_eq!(postfix, "12-3+4-");
|
|
|
}
|
|
|
</code></pre></pre>
|
|
|
<h2><a class="header" href="#discussion-10" id="discussion-10">Discussion</a></h2>
|
|
|
<p>There may be a wrong perception that the Interpreter design pattern is about design
|
|
|
grammars for formal languages and implementation of parsers for these grammars.
|
|
|
In fact, this pattern is about expressing problem instances in a more specific
|
|
|
way and implementing functions/classes/structs that solve these problem instances.
|
|
|
Rust language has <code>macro_rules!</code> that allow to define special syntax and rules
|
|
|
on how to expand this syntax into source code.</p>
|
|
|
<p>In the following example we create a simple <code>macro_rules!</code> that computes
|
|
|
<a href="https://en.wikipedia.org/wiki/Euclidean_distance">Euclidean length</a> of <code>n</code>
|
|
|
dimensional vectors. Writing <code>norm!(x,1,2)</code> might be easier to express and more
|
|
|
efficient than packing <code>x,1,2</code> into a <code>Vec</code> and calling a function computing
|
|
|
the length.</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">macro_rules! norm {
|
|
|
($($element:expr),*) => {
|
|
|
{
|
|
|
let mut n = 0.0;
|
|
|
$(
|
|
|
n += ($element as f64)*($element as f64);
|
|
|
)*
|
|
|
n.sqrt()
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
|
|
|
fn main() {
|
|
|
let x = -3f64;
|
|
|
let y = 4f64;
|
|
|
|
|
|
assert_eq!(3f64, norm!(x));
|
|
|
assert_eq!(5f64, norm!(x, y));
|
|
|
assert_eq!(0f64, norm!(0, 0, 0));
|
|
|
assert_eq!(1f64, norm!(0.5, -0.5, 0.5, -0.5));
|
|
|
}
|
|
|
</code></pre></pre>
|
|
|
<h2><a class="header" href="#see-also-11" id="see-also-11">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Interpreter_pattern">Interpreter pattern</a></li>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Context-free_grammar">Context free grammar</a></li>
|
|
|
<li><a href="https://doc.rust-lang.org/rust-by-example/macros.html">macro_rules!</a></li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#newtype" id="newtype">Newtype</a></h1>
|
|
|
<p>What if in some cases we want a type to behave similar to another type or
|
|
|
enforce some behaviour at compile time where using only type aliases would
|
|
|
not be enough?</p>
|
|
|
<p>For example, if we want to create a custom <code>Display</code> implementation for <code>String</code>
|
|
|
due to security considerations (e.g. passwords).</p>
|
|
|
<p>For such cases we could use the <code>Newtype</code> pattern to provide <strong>type safety</strong>
|
|
|
and <strong>encapsulation</strong>.</p>
|
|
|
<h2><a class="header" href="#description-23" id="description-23">Description</a></h2>
|
|
|
<p>Use a tuple struct with a single field to make an opaque wrapper for a type.
|
|
|
This creates a new type, rather than an alias to a type (<code>type</code> items).</p>
|
|
|
<h2><a class="header" href="#example-16" id="example-16">Example</a></h2>
|
|
|
<pre><code class="language-rust ignore">// Some type, not necessarily in the same module or even crate.
|
|
|
struct Foo {
|
|
|
//..
|
|
|
}
|
|
|
|
|
|
impl Foo {
|
|
|
// These functions are not present on Bar.
|
|
|
//..
|
|
|
}
|
|
|
|
|
|
// The newtype.
|
|
|
pub struct Bar(Foo);
|
|
|
|
|
|
impl Bar {
|
|
|
// Constructor.
|
|
|
pub fn new(
|
|
|
//..
|
|
|
) -> Bar {
|
|
|
|
|
|
//..
|
|
|
|
|
|
}
|
|
|
|
|
|
//..
|
|
|
}
|
|
|
|
|
|
fn main() {
|
|
|
let b = Bar::new(...);
|
|
|
|
|
|
// Foo and Bar are type incompatible, the following do not type check.
|
|
|
// let f: Foo = b;
|
|
|
// let b: Bar = Foo { ... };
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#motivation-13" id="motivation-13">Motivation</a></h2>
|
|
|
<p>The primary motivation for newtypes is abstraction. It allows you to share
|
|
|
implementation details between types while precisely controlling the interface.
|
|
|
By using a newtype rather than exposing the implementation type as part of an
|
|
|
API, it allows you to change implementation backwards compatibly.</p>
|
|
|
<p>Newtypes can be used for distinguishing units, e.g., wrapping <code>f64</code> to give
|
|
|
distinguishable <code>Miles</code> and <code>Kms</code>.</p>
|
|
|
<h2><a class="header" href="#advantages-16" id="advantages-16">Advantages</a></h2>
|
|
|
<p>The wrapped and wrapper types are not type compatible (as opposed to using
|
|
|
<code>type</code>), so users of the newtype will never 'confuse' the wrapped and wrapper
|
|
|
types.</p>
|
|
|
<p>Newtypes are a zero-cost abstraction - there is no runtime overhead.</p>
|
|
|
<p>The privacy system ensures that users cannot access the wrapped type (if the
|
|
|
field is private, which it is by default).</p>
|
|
|
<h2><a class="header" href="#disadvantages-16" id="disadvantages-16">Disadvantages</a></h2>
|
|
|
<p>The downside of newtypes (especially compared with type aliases), is that there
|
|
|
is no special language support. This means there can be <em>a lot</em> of boilerplate.
|
|
|
You need a 'pass through' method for every method you want to expose on the
|
|
|
wrapped type, and an impl for every trait you want to also be implemented for
|
|
|
the wrapper type.</p>
|
|
|
<h2><a class="header" href="#discussion-11" id="discussion-11">Discussion</a></h2>
|
|
|
<p>Newtypes are very common in Rust code. Abstraction or representing units are the
|
|
|
most common uses, but they can be used for other reasons:</p>
|
|
|
<ul>
|
|
|
<li>restricting functionality (reduce the functions exposed or traits implemented),</li>
|
|
|
<li>making a type with copy semantics have move semantics,</li>
|
|
|
<li>abstraction by providing a more concrete type and thus hiding internal types,
|
|
|
e.g.,</li>
|
|
|
</ul>
|
|
|
<pre><code class="language-rust ignore">pub struct Foo(Bar<T1, T2>);
|
|
|
</code></pre>
|
|
|
<p>Here, <code>Bar</code> might be some public, generic type and <code>T1</code> and <code>T2</code> are some internal
|
|
|
types. Users of our module shouldn't know that we implement <code>Foo</code> by using a <code>Bar</code>,
|
|
|
but what we're really hiding here is the types <code>T1</code> and <code>T2</code>, and how they are used
|
|
|
with <code>Bar</code>.</p>
|
|
|
<h2><a class="header" href="#see-also-12" id="see-also-12">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://doc.rust-lang.org/book/ch19-04-advanced-types.html?highlight=newtype#using-the-newtype-pattern-for-type-safety-and-abstraction">Advanced Types in the book</a></li>
|
|
|
<li><a href="https://wiki.haskell.org/Newtype">Newtypes in Haskell</a></li>
|
|
|
<li><a href="https://doc.rust-lang.org/stable/book/ch19-04-advanced-types.html#creating-type-synonyms-with-type-aliases">Type aliases</a></li>
|
|
|
<li><a href="https://crates.io/crates/derive_more">derive_more</a>, a crate for deriving many
|
|
|
builtin traits on newtypes.</li>
|
|
|
<li><a href="https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html">The Newtype Pattern In Rust</a></li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#raii-with-guards" id="raii-with-guards">RAII with guards</a></h1>
|
|
|
<h2><a class="header" href="#description-24" id="description-24">Description</a></h2>
|
|
|
<p><a href="https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">RAII</a> stands for "Resource Acquisition is Initialisation" which is a
|
|
|
terrible name. The essence of the pattern is that resource initialisation is done
|
|
|
in the constructor of an object and finalisation in the destructor. This pattern
|
|
|
is extended in Rust by using an RAII object as a guard of some resource and relying
|
|
|
on the type system to ensure that access is always mediated by the guard object.</p>
|
|
|
<h2><a class="header" href="#example-17" id="example-17">Example</a></h2>
|
|
|
<p>Mutex guards are the classic example of this pattern from the std library (this
|
|
|
is a simplified version of the real implementation):</p>
|
|
|
<pre><code class="language-rust ignore">use std::ops::Deref;
|
|
|
|
|
|
struct Foo {}
|
|
|
|
|
|
struct Mutex<T> {
|
|
|
// We keep a reference to our data: T here.
|
|
|
//..
|
|
|
}
|
|
|
|
|
|
struct MutexGuard<'a, T: 'a> {
|
|
|
data: &'a T,
|
|
|
//..
|
|
|
}
|
|
|
|
|
|
// Locking the mutex is explicit.
|
|
|
impl<T> Mutex<T> {
|
|
|
fn lock(&self) -> MutexGuard<T> {
|
|
|
// Lock the underlying OS mutex.
|
|
|
//..
|
|
|
|
|
|
// MutexGuard keeps a reference to self
|
|
|
MutexGuard {
|
|
|
data: self,
|
|
|
//..
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Destructor for unlocking the mutex.
|
|
|
impl<'a, T> Drop for MutexGuard<'a, T> {
|
|
|
fn drop(&mut self) {
|
|
|
// Unlock the underlying OS mutex.
|
|
|
//..
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Implementing Deref means we can treat MutexGuard like a pointer to T.
|
|
|
impl<'a, T> Deref for MutexGuard<'a, T> {
|
|
|
type Target = T;
|
|
|
|
|
|
fn deref(&self) -> &T {
|
|
|
self.data
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fn baz(x: Mutex<Foo>) {
|
|
|
let xx = x.lock();
|
|
|
xx.foo(); // foo is a method on Foo.
|
|
|
// The borrow checker ensures we can't store a reference to the underlying
|
|
|
// Foo which will outlive the guard xx.
|
|
|
|
|
|
// x is unlocked when we exit this function and xx's destructor is executed.
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#motivation-14" id="motivation-14">Motivation</a></h2>
|
|
|
<p>Where a resource must be finalised after use, RAII can be used to do this
|
|
|
finalisation. If it is an error to access that resource after finalisation, then
|
|
|
this pattern can be used to prevent such errors.</p>
|
|
|
<h2><a class="header" href="#advantages-17" id="advantages-17">Advantages</a></h2>
|
|
|
<p>Prevents errors where a resource is not finalised and where a resource is used
|
|
|
after finalisation.</p>
|
|
|
<h2><a class="header" href="#discussion-12" id="discussion-12">Discussion</a></h2>
|
|
|
<p>RAII is a useful pattern for ensuring resources are properly deallocated or
|
|
|
finalised. We can make use of the borrow checker in Rust to statically prevent
|
|
|
errors stemming from using resources after finalisation takes place.</p>
|
|
|
<p>The core aim of the borrow checker is to ensure that references to data do not
|
|
|
outlive that data. The RAII guard pattern works because the guard object
|
|
|
contains a reference to the underlying resource and only exposes such
|
|
|
references. Rust ensures that the guard cannot outlive the underlying resource
|
|
|
and that references to the resource mediated by the guard cannot outlive the
|
|
|
guard. To see how this works it is helpful to examine the signature of <code>deref</code>
|
|
|
without lifetime elision:</p>
|
|
|
<pre><code class="language-rust ignore">fn deref<'a>(&'a self) -> &'a T {
|
|
|
//..
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>The returned reference to the resource has the same lifetime as <code>self</code> (<code>'a</code>).
|
|
|
The borrow checker therefore ensures that the lifetime of the reference to <code>T</code>
|
|
|
is shorter than the lifetime of <code>self</code>.</p>
|
|
|
<p>Note that implementing <code>Deref</code> is not a core part of this pattern, it only makes
|
|
|
using the guard object more ergonomic. Implementing a <code>get</code> method on the guard
|
|
|
works just as well.</p>
|
|
|
<h2><a class="header" href="#see-also-13" id="see-also-13">See also</a></h2>
|
|
|
<p><a href="patterns/../idioms/dtor-finally.html">Finalisation in destructors idiom</a></p>
|
|
|
<p>RAII is a common pattern in C++: <a href="http://en.cppreference.com/w/cpp/language/raii">cppreference.com</a>,
|
|
|
<a href="https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">wikipedia</a>.</p>
|
|
|
<p><a href="https://doc.rust-lang.org/1.0.0/style/ownership/raii.html">Style guide entry</a>
|
|
|
(currently just a placeholder).</p>
|
|
|
<h1><a class="header" href="#prefer-small-crates" id="prefer-small-crates">Prefer small crates</a></h1>
|
|
|
<h2><a class="header" href="#description-25" id="description-25">Description</a></h2>
|
|
|
<p>Prefer small crates that do one thing well.</p>
|
|
|
<p>Cargo and crates.io make it easy to add third-party libraries, much more so than
|
|
|
in say C or C++. Moreover, since packages on crates.io cannot be edited or removed
|
|
|
after publication, any build that works now should continue to work in the future.
|
|
|
We should take advantage of this tooling, and use smaller, more fine-grained dependencies.</p>
|
|
|
<h2><a class="header" href="#advantages-18" id="advantages-18">Advantages</a></h2>
|
|
|
<ul>
|
|
|
<li>Small crates are easier to understand, and encourage more modular code.</li>
|
|
|
<li>Crates allow for re-using code between projects.
|
|
|
For example, the <code>url</code> crate was developed as part of the Servo browser engine,
|
|
|
but has since found wide use outside the project. * Since the compilation unit
|
|
|
of Rust is the crate, splitting a project into multiple crates can allow more of
|
|
|
the code to be built in parallel.</li>
|
|
|
</ul>
|
|
|
<h2><a class="header" href="#disadvantages-17" id="disadvantages-17">Disadvantages</a></h2>
|
|
|
<ul>
|
|
|
<li>This can lead to "dependency hell", when a project depends on multiple conflicting
|
|
|
versions of a crate at the same time. For example, the <code>url</code> crate has both versions
|
|
|
1.0 and 0.5. Since the <code>Url</code> from <code>url:1.0</code> and the <code>Url</code> from <code>url:0.5</code> are
|
|
|
different types, an HTTP client that uses <code>url:0.5</code> would not accept <code>Url</code> values
|
|
|
from a web scraper that uses <code>url:1.0</code>.</li>
|
|
|
<li>Packages on crates.io are not curated. A crate may be poorly written, have
|
|
|
unhelpful documentation, or be outright malicious.</li>
|
|
|
<li>Two small crates may be less optimized than one large one, since the compiler
|
|
|
does not perform link-time optimization (LTO) by default.</li>
|
|
|
</ul>
|
|
|
<h2><a class="header" href="#examples-1" id="examples-1">Examples</a></h2>
|
|
|
<p>The <a href="https://crates.io/crates/ref_slice"><code>ref_slice</code></a> crate provides functions
|
|
|
for converting <code>&T</code> to <code>&[T]</code>.</p>
|
|
|
<p>The <a href="https://crates.io/crates/url"><code>url</code></a> crate provides tools for working with
|
|
|
URLs.</p>
|
|
|
<p>The <a href="https://crates.io/crates/num_cpus"><code>num_cpus</code></a> crate provides a function to
|
|
|
query the number of CPUs on a machine.</p>
|
|
|
<h2><a class="header" href="#see-also-14" id="see-also-14">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://crates.io/">crates.io: The Rust community crate host</a></li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#strategy-aka-policy" id="strategy-aka-policy">Strategy (aka Policy)</a></h1>
|
|
|
<h2><a class="header" href="#description-26" id="description-26">Description</a></h2>
|
|
|
<p>The <a href="https://en.wikipedia.org/wiki/Strategy_pattern">Strategy design pattern</a>
|
|
|
is a technique that enables separation of concerns.
|
|
|
It also allows to decouple software modules through <a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion</a>.</p>
|
|
|
<p>The basic idea behind the Strategy pattern is that, given an algorithm solving
|
|
|
a particular problem, we define only the skeleton of the algorithm at an abstract
|
|
|
level and we separate the specific algorithm’s implementation into different parts.</p>
|
|
|
<p>In this way, a client using the algorithm may choose a specific implementation,
|
|
|
while the general algorithm workflow remains the same. In other words, the abstract
|
|
|
specification of the class does not depend on the specific implementation of the
|
|
|
derived class, but specific implementation must adhere to the abstract specification.
|
|
|
This is why we call it "Dependency Inversion".</p>
|
|
|
<h2><a class="header" href="#motivation-15" id="motivation-15">Motivation</a></h2>
|
|
|
<p>Imagine we are working on a project that generates reports every month.
|
|
|
We need the reports to be generated in different formats (strategies), e.g.,
|
|
|
in <code>JSON</code> or <code>Plain Text</code> formats.
|
|
|
But things vary over time and we don't know what kind of requirement we may get
|
|
|
in the future. For example, we may need to generate our report in a completly new
|
|
|
format, or just modify one of the existing formats.</p>
|
|
|
<h2><a class="header" href="#example-18" id="example-18">Example</a></h2>
|
|
|
<p>In this example our invariants (or abstractions) are <code>Context</code>, <code>Formatter</code>,
|
|
|
and <code>Report</code>, while <code>Text</code> and <code>Json</code> are our strategy structs. These strategies
|
|
|
have to implement the <code>Formatter</code> trait.</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">use std::collections::HashMap;
|
|
|
type Data = HashMap<String, u32>;
|
|
|
|
|
|
trait Formatter {
|
|
|
fn format(&self, data: &Data, s: &mut String);
|
|
|
}
|
|
|
|
|
|
struct Report;
|
|
|
|
|
|
impl Report {
|
|
|
fn generate<T: Formatter>(g: T, s: &mut String) {
|
|
|
// backend operations...
|
|
|
let mut data = HashMap::new();
|
|
|
data.insert("one".to_string(), 1);
|
|
|
data.insert("two".to_string(), 2);
|
|
|
// generate report
|
|
|
g.format(&data, s);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
struct Text;
|
|
|
impl Formatter for Text {
|
|
|
fn format(&self, data: &Data, s: &mut String) {
|
|
|
*s = data
|
|
|
.iter()
|
|
|
.map(|(key, val)| format!("{} {}\n", key, val))
|
|
|
.collect();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
struct Json;
|
|
|
impl Formatter for Json {
|
|
|
fn format(&self, data: &Data, s: &mut String) {
|
|
|
*s = String::from("[");
|
|
|
let mut iter = data.into_iter();
|
|
|
if let Some((key, val)) = iter.next() {
|
|
|
let entry = format!(r#"{{"{}":"{}"}}"#, key, val);
|
|
|
s.push_str(&entry);
|
|
|
while let Some((key, val)) = iter.next() {
|
|
|
s.push(',');
|
|
|
let entry = format!(r#"{{"{}":"{}"}}"#, key, val);
|
|
|
s.push_str(&entry);
|
|
|
}
|
|
|
}
|
|
|
s.push(']');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fn main() {
|
|
|
let mut s = String::from("");
|
|
|
Report::generate(Text, &mut s);
|
|
|
assert!(s.contains("one 1"));
|
|
|
assert!(s.contains("two 2"));
|
|
|
|
|
|
Report::generate(Json, &mut s);
|
|
|
assert!(s.contains(r#"{"one":"1"}"#));
|
|
|
assert!(s.contains(r#"{"two":"2"}"#));
|
|
|
}
|
|
|
</code></pre></pre>
|
|
|
<h2><a class="header" href="#advantages-19" id="advantages-19">Advantages</a></h2>
|
|
|
<p>The main advantage is separation of concerns. For example, in this case <code>Report</code>
|
|
|
does not know anything about specific implementations of <code>Json</code> and <code>Text</code>,
|
|
|
whereas the output implementations does not care about how data is preprocessed,
|
|
|
stored, and fetched. The only thing they have to know is context and a specific
|
|
|
trait and method to implement, i.e,<code>Formatter</code> and <code>run</code>.</p>
|
|
|
<h2><a class="header" href="#disadvantages-18" id="disadvantages-18">Disadvantages</a></h2>
|
|
|
<p>For each strategy there must be implemented at least one module, so number of modules
|
|
|
increases with number of strategies. If there are many strategies to choose from
|
|
|
then users have to know how strategies differ from one another.</p>
|
|
|
<h2><a class="header" href="#discussion-13" id="discussion-13">Discussion</a></h2>
|
|
|
<p>In the previous example all strategies are implemented in a single file.
|
|
|
Ways of providing different strategies includes:</p>
|
|
|
<ul>
|
|
|
<li>All in one file (as shown in this example, similar to being separated as modules)</li>
|
|
|
<li>Separated as modules, E.g. <code>formatter::json</code> module, <code>formatter::text</code> module</li>
|
|
|
<li>Use compiler feature flags, E.g. <code>json</code> feature, <code>text</code> feature</li>
|
|
|
<li>Separated as crates, E.g. <code>json</code> crate, <code>text</code> crate</li>
|
|
|
</ul>
|
|
|
<p>Serde crate is a good example of the <code>Strategy</code> pattern in action. Serde allows
|
|
|
<a href="https://serde.rs/custom-serialization.html">full customization</a> of the serialization
|
|
|
behavior by manually implementing <code>Serialize</code> and <code>Deserialize</code> traits for our
|
|
|
type. For example, we could easily swap <code>serde_json</code> with <code>serde_cbor</code> since they
|
|
|
expose similar methods. Having this makes the helper crate <code>serde_transcode</code> much
|
|
|
more useful and ergonomic.</p>
|
|
|
<p>However, we don't need to use traits in order to design this pattern in Rust.</p>
|
|
|
<p>The following toy example demonstrates the idea of the Strategy pattern using Rust
|
|
|
<code>closures</code>:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">struct Adder;
|
|
|
impl Adder {
|
|
|
pub fn add<F>(x: u8, y: u8, f: F) -> u8
|
|
|
where
|
|
|
F: Fn(u8, u8) -> u8,
|
|
|
{
|
|
|
f(x, y)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fn main() {
|
|
|
let arith_adder = |x, y| x + y;
|
|
|
let bool_adder = |x, y| {
|
|
|
if x == 1 || y == 1 {
|
|
|
1
|
|
|
} else {
|
|
|
0
|
|
|
}
|
|
|
};
|
|
|
let custom_adder = |x, y| 2 * x + y;
|
|
|
|
|
|
assert_eq!(9, Adder::add(4, 5, arith_adder));
|
|
|
assert_eq!(0, Adder::add(0, 0, bool_adder));
|
|
|
assert_eq!(5, Adder::add(1, 3, custom_adder));
|
|
|
}
|
|
|
|
|
|
</code></pre></pre>
|
|
|
<p>In fact, Rust already uses this idea for <code>Options</code>'s <code>map</code> method:</p>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">fn main() {
|
|
|
let val = Some("Rust");
|
|
|
|
|
|
let len_strategy = |s: &str| s.len();
|
|
|
assert_eq!(4, val.map(len_strategy).unwrap());
|
|
|
|
|
|
let first_byte_strategy = |s: &str| s.bytes().next().unwrap();
|
|
|
assert_eq!(82, val.map(first_byte_strategy).unwrap());
|
|
|
}
|
|
|
</code></pre></pre>
|
|
|
<h2><a class="header" href="#see-also-15" id="see-also-15">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Strategy_pattern">Strategy Pattern</a></li>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Dependency_injection">Dependency Injection</a></li>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Modern_C++_Design#Policy-based_design">Policy Based Design</a></li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#contain-unsafety-in-small-modules" id="contain-unsafety-in-small-modules">Contain unsafety in small modules</a></h1>
|
|
|
<h2><a class="header" href="#description-27" id="description-27">Description</a></h2>
|
|
|
<p>If you have <code>unsafe</code> code, create the smallest possible module that can uphold
|
|
|
the needed invariants to build a minimal safe interface upon the unsafety. Embed
|
|
|
this into a larger module that contains only safe code and presents an ergonomi
|
|
|
interface. Note that the outer module can contain unsafe functions and methods
|
|
|
that call directly into the unsafe code. Users may use this to gain speed benefits.</p>
|
|
|
<h2><a class="header" href="#advantages-20" id="advantages-20">Advantages</a></h2>
|
|
|
<ul>
|
|
|
<li>This restricts the unsafe code that must be audited</li>
|
|
|
<li>Writing the outer module is much easier, since you can count on the guarantees
|
|
|
of the inner module</li>
|
|
|
</ul>
|
|
|
<h2><a class="header" href="#disadvantages-19" id="disadvantages-19">Disadvantages</a></h2>
|
|
|
<ul>
|
|
|
<li>Sometimes, it may be hard to find a suitable interface.</li>
|
|
|
<li>The abstraction may introduce inefficiencies.</li>
|
|
|
</ul>
|
|
|
<h2><a class="header" href="#examples-2" id="examples-2">Examples</a></h2>
|
|
|
<ul>
|
|
|
<li>The <a href="https://docs.rs/toolshed"><code>toolshed</code></a> crate contains its unsafe operations
|
|
|
in submodules, presenting a safe interface to users. * <code>std</code>s <code>String</code> class
|
|
|
is a wrapper over <code>Vec<u8></code> with the added invariant that the contents must be
|
|
|
valid UTF-8. The operations on <code>String</code> ensure this behavior. However, users
|
|
|
have the option of using an <code>unsafe</code> method to create a <code>String</code>, in which case
|
|
|
the onus is on them to guarantee the validity of the contents.</li>
|
|
|
</ul>
|
|
|
<h2><a class="header" href="#see-also-16" id="see-also-16">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://www.ralfj.de/blog/2018/08/22/two-kinds-of-invariants.html">Ralf Jung's Blog about invariants in unsafe code</a></li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#visitor" id="visitor">Visitor</a></h1>
|
|
|
<h2><a class="header" href="#description-28" id="description-28">Description</a></h2>
|
|
|
<p>A visitor encapsulates an algorithm that operates over a heterogeneous
|
|
|
collection of objects. It allows multiple different algorithms to be written
|
|
|
over the same data without having to modify the data (or their primary
|
|
|
behaviour).</p>
|
|
|
<p>Furthermore, the visitor pattern allows separating the traversal of
|
|
|
a collection of objects from the operations performed on each object.</p>
|
|
|
<h2><a class="header" href="#example-19" id="example-19">Example</a></h2>
|
|
|
<pre><code class="language-rust ignore">// The data we will visit
|
|
|
mod ast {
|
|
|
pub enum Stmt {
|
|
|
Expr(Expr),
|
|
|
Let(Name, Expr),
|
|
|
}
|
|
|
|
|
|
pub struct Name {
|
|
|
value: String,
|
|
|
}
|
|
|
|
|
|
pub enum Expr {
|
|
|
IntLit(i64),
|
|
|
Add(Box<Expr>, Box<Expr>),
|
|
|
Sub(Box<Expr>, Box<Expr>),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// The abstract visitor
|
|
|
mod visit {
|
|
|
use ast::*;
|
|
|
|
|
|
pub trait Visitor<T> {
|
|
|
fn visit_name(&mut self, n: &Name) -> T;
|
|
|
fn visit_stmt(&mut self, s: &Stmt) -> T;
|
|
|
fn visit_expr(&mut self, e: &Expr) -> T;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
use visit::*;
|
|
|
use ast::*;
|
|
|
|
|
|
// An example concrete implementation - walks the AST interpreting it as code.
|
|
|
struct Interpreter;
|
|
|
impl Visitor<i64> for Interpreter {
|
|
|
fn visit_name(&mut self, n: &Name) -> i64 { panic!() }
|
|
|
fn visit_stmt(&mut self, s: &Stmt) -> i64 {
|
|
|
match *s {
|
|
|
Stmt::Expr(ref e) => self.visit_expr(e),
|
|
|
Stmt::Let(..) => unimplemented!(),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fn visit_expr(&mut self, e: &Expr) -> i64 {
|
|
|
match *e {
|
|
|
Expr::IntLit(n) => n,
|
|
|
Expr::Add(ref lhs, ref rhs) => self.visit_expr(lhs) + self.visit_expr(rhs),
|
|
|
Expr::Sub(ref lhs, ref rhs) => self.visit_expr(lhs) - self.visit_expr(rhs),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>One could implement further visitors, for example a type checker, without having
|
|
|
to modify the AST data.</p>
|
|
|
<h2><a class="header" href="#motivation-16" id="motivation-16">Motivation</a></h2>
|
|
|
<p>The visitor pattern is useful anywhere that you want to apply an algorithm to
|
|
|
heterogeneous data. If data is homogeneous, you can use an iterator-like pattern.
|
|
|
Using a visitor object (rather than a functional approach) allows the visitor to
|
|
|
be stateful and thus communicate information between nodes.</p>
|
|
|
<h2><a class="header" href="#discussion-14" id="discussion-14">Discussion</a></h2>
|
|
|
<p>It is common for the <code>visit_*</code> methods to return void (as opposed to in the
|
|
|
example). In that case it is possible to factor out the traversal code and share
|
|
|
it between algorithms (and also to provide noop default methods). In Rust, the
|
|
|
common way to do this is to provide <code>walk_*</code> functions for each datum. For
|
|
|
example,</p>
|
|
|
<pre><code class="language-rust ignore">pub fn walk_expr(visitor: &mut Visitor, e: &Expr) {
|
|
|
match *e {
|
|
|
Expr::IntLit(_) => {},
|
|
|
Expr::Add(ref lhs, ref rhs) => {
|
|
|
visitor.visit_expr(lhs);
|
|
|
visitor.visit_expr(rhs);
|
|
|
}
|
|
|
Expr::Sub(ref lhs, ref rhs) => {
|
|
|
visitor.visit_expr(lhs);
|
|
|
visitor.visit_expr(rhs);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>In other languages (e.g., Java) it is common for data to have an <code>accept</code> method
|
|
|
which performs the same duty.</p>
|
|
|
<h2><a class="header" href="#see-also-17" id="see-also-17">See also</a></h2>
|
|
|
<p>The visitor pattern is a common pattern in most OO languages.</p>
|
|
|
<p><a href="https://en.wikipedia.org/wiki/Visitor_pattern">Wikipedia article</a></p>
|
|
|
<p>The <a href="patterns/fold.html">fold</a> pattern is similar to visitor but produces a new version of
|
|
|
the visited data structure.</p>
|
|
|
<h1><a class="header" href="#anti-patterns" id="anti-patterns">Anti-patterns</a></h1>
|
|
|
<p>An <a href="https://en.wikipedia.org/wiki/Anti-pattern">anti-pattern</a> is a solution to
|
|
|
a "recurring problem that is usually ineffective and risks being highly
|
|
|
counterproductive". Just as valuable as knowing how to solve a problem, is
|
|
|
knowing how <em>not</em> to solve it. Anti-patterns give us great counter-examples to
|
|
|
consider relative to design patterns. Anti-patterns are not confined to code.
|
|
|
For example, a process can be an anti-pattern, too.</p>
|
|
|
<h1><a class="header" href="#denywarnings" id="denywarnings"><code>#![deny(warnings)]</code></a></h1>
|
|
|
<h2><a class="header" href="#description-29" id="description-29">Description</a></h2>
|
|
|
<p>A well-intentioned crate author wants to ensure their code builds without
|
|
|
warnings. So they annotate their crate root with the following:</p>
|
|
|
<h2><a class="header" href="#example-20" id="example-20">Example</a></h2>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span>#![deny(warnings)]
|
|
|
|
|
|
<span class="boring">fn main() {
|
|
|
</span>// All is well.
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<h2><a class="header" href="#advantages-21" id="advantages-21">Advantages</a></h2>
|
|
|
<p>It is short and will stop the build if anything is amiss.</p>
|
|
|
<h2><a class="header" href="#drawbacks" id="drawbacks">Drawbacks</a></h2>
|
|
|
<p>By disallowing the compiler to build with warnings, a crate author opts out of
|
|
|
Rust's famed stability. Sometimes new features or old misfeatures need a change
|
|
|
in how things are done, thus lints are written that <code>warn</code> for a certain grace
|
|
|
period before being turned to <code>deny</code>.</p>
|
|
|
<p>For example, it was discovered that a type could have two <code>impl</code>s with the same
|
|
|
method. This was deemed a bad idea, but in order to make the transition smooth,
|
|
|
the <code>overlapping-inherent-impls</code> lint was introduced to give a warning to those
|
|
|
stumbling on this fact, before it becomes a hard error in a future release.</p>
|
|
|
<p>Also sometimes APIs get deprecated, so their use will emit a warning where
|
|
|
before there was none.</p>
|
|
|
<p>All this conspires to potentially break the build whenever something changes.</p>
|
|
|
<p>Furthermore, crates that supply additional lints (e.g. <a href="https://github.com/Manishearth/rust-clippy">rust-clippy</a>) can no
|
|
|
longer be used unless the annotation is removed. This is mitigated with
|
|
|
<a href="https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints">--cap-lints</a>. The <code>--cap-lints=warn</code> command line argument, turns all <code>deny</code>
|
|
|
lint errors into warnings. But be aware that <code>forbid</code> lints are stronger than
|
|
|
<code>deny</code> hence the 'forbid' level cannot be overridden to be anything lower than
|
|
|
an error. As a result <code>forbid</code> lints will still stop compilation.</p>
|
|
|
<h2><a class="header" href="#alternatives" id="alternatives">Alternatives</a></h2>
|
|
|
<p>There are two ways of tackling this problem: First, we can decouple the build
|
|
|
setting from the code, and second, we can name the lints we want to deny
|
|
|
explicitly.</p>
|
|
|
<p>The following command line will build with all warnings set to <code>deny</code>:</p>
|
|
|
<p><code>RUSTFLAGS="-D warnings" cargo build</code></p>
|
|
|
<p>This can be done by any individual developer (or be set in a CI tool like
|
|
|
Travis, but remember that this may break the build when something changes)
|
|
|
without requiring a change to the code.</p>
|
|
|
<p>Alternatively, we can specify the lints that we want to <code>deny</code> in the code.
|
|
|
Here is a list of warning lints that is (hopefully) safe to deny (as of Rustc 1.48.0):</p>
|
|
|
<pre><code class="language-rust ignore">#[deny(bad-style,
|
|
|
const-err,
|
|
|
dead-code,
|
|
|
improper-ctypes,
|
|
|
non-shorthand-field-patterns,
|
|
|
no-mangle-generic-items,
|
|
|
overflowing-literals,
|
|
|
path-statements ,
|
|
|
patterns-in-fns-without-body,
|
|
|
private-in-public,
|
|
|
unconditional-recursion,
|
|
|
unused,
|
|
|
unused-allocation,
|
|
|
unused-comparisons,
|
|
|
unused-parens,
|
|
|
while-true)]
|
|
|
</code></pre>
|
|
|
<p>In addition, the following <code>allow</code>ed lints may be a good idea to <code>deny</code>:</p>
|
|
|
<pre><code class="language-rust ignore">#[deny(missing-debug-implementations,
|
|
|
missing-docs,
|
|
|
trivial-casts,
|
|
|
trivial-numeric-casts,
|
|
|
unused-extern-crates,
|
|
|
unused-import-braces,
|
|
|
unused-qualifications,
|
|
|
unused-results)]
|
|
|
</code></pre>
|
|
|
<p>Some may also want to add <code>missing-copy-implementations</code> to their list.</p>
|
|
|
<p>Note that we explicitly did not add the <code>deprecated</code> lint, as it is fairly
|
|
|
certain that there will be more deprecated APIs in the future.</p>
|
|
|
<h2><a class="header" href="#see-also-18" id="see-also-18">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://rust-lang.github.io/rust-clippy/master">A collection of all clippy lints</a></li>
|
|
|
<li><a href="https://doc.rust-lang.org/reference/attributes.html#deprecation">deprecate attribute</a> documentation</li>
|
|
|
<li>Type <code>rustc -W help</code> for a list of lints on your system. Also type
|
|
|
<code>rustc --help</code> for a general list of options</li>
|
|
|
<li><a href="https://github.com/Manishearth/rust-clippy">rust-clippy</a> is a collection of lints for better Rust code</li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#deref-polymorphism" id="deref-polymorphism"><code>Deref</code> polymorphism</a></h1>
|
|
|
<h2><a class="header" href="#description-30" id="description-30">Description</a></h2>
|
|
|
<p>Abuse the <code>Deref</code> trait to emulate inheritance between structs, and thus reuse
|
|
|
methods.</p>
|
|
|
<h2><a class="header" href="#example-21" id="example-21">Example</a></h2>
|
|
|
<p>Sometimes we want to emulate the following common pattern from OO languages such
|
|
|
as Java:</p>
|
|
|
<pre><code class="language-java">class Foo {
|
|
|
void m() { ... }
|
|
|
}
|
|
|
|
|
|
class Bar extends Foo {}
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
Bar b = new Bar();
|
|
|
b.m();
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>We can use the deref polymorphism anti-pattern to do so:</p>
|
|
|
<pre><code class="language-rust ignore">use std::ops::Deref;
|
|
|
|
|
|
struct Foo {}
|
|
|
|
|
|
impl Foo {
|
|
|
fn m(&self) {
|
|
|
//..
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
struct Bar {
|
|
|
f: Foo
|
|
|
}
|
|
|
|
|
|
impl Deref for Bar {
|
|
|
type Target = Foo;
|
|
|
fn deref(&self) -> &Foo {
|
|
|
&self.f
|
|
|
}
|
|
|
}
|
|
|
|
|
|
fn main() {
|
|
|
let b = Bar { Foo {} };
|
|
|
b.m();
|
|
|
}
|
|
|
</code></pre>
|
|
|
<p>There is no struct inheritance in Rust. Instead we use composition and include
|
|
|
an instance of <code>Foo</code> in <code>Bar</code> (since the field is a value, it is stored inline,
|
|
|
so if there were fields, they would have the same layout in memory as the Java
|
|
|
version (probably, you should use <code>#[repr(C)]</code> if you want to be sure)).</p>
|
|
|
<p>In order to make the method call work we implement <code>Deref</code> for <code>Bar</code> with <code>Foo</code>
|
|
|
as the target (returning the embedded <code>Foo</code> field). That means that when we
|
|
|
dereference a <code>Bar</code> (for example, using <code>*</code>) then we will get a <code>Foo</code>. That is
|
|
|
pretty weird. Dereferencing usually gives a <code>T</code> from a reference to <code>T</code>, here we
|
|
|
have two unrelated types. However, since the dot operator does implicit
|
|
|
dereferencing, it means that the method call will search for methods on <code>Foo</code> as
|
|
|
well as <code>Bar</code>.</p>
|
|
|
<h2><a class="header" href="#advantages-22" id="advantages-22">Advantages</a></h2>
|
|
|
<p>You save a little boilerplate, e.g.,</p>
|
|
|
<pre><code class="language-rust ignore">impl Bar {
|
|
|
fn m(&self) {
|
|
|
self.f.m()
|
|
|
}
|
|
|
}
|
|
|
</code></pre>
|
|
|
<h2><a class="header" href="#disadvantages-20" id="disadvantages-20">Disadvantages</a></h2>
|
|
|
<p>Most importantly this is a surprising idiom - future programmers reading this in
|
|
|
code will not expect this to happen. That's because we are abusing the <code>Deref</code>
|
|
|
trait rather than using it as intended (and documented, etc.). It's also because
|
|
|
the mechanism here is completely implicit.</p>
|
|
|
<p>This pattern does not introduce subtyping between <code>Foo</code> and <code>Bar</code> like
|
|
|
inheritance in Java or C++ does. Furthermore, traits implemented by <code>Foo</code> are
|
|
|
not automatically implemented for <code>Bar</code>, so this pattern interacts badly with
|
|
|
bounds checking and thus generic programming.</p>
|
|
|
<p>Using this pattern gives subtly different semantics from most OO languages with
|
|
|
regards to <code>self</code>. Usually it remains a reference to the sub-class, with this
|
|
|
pattern it will be the 'class' where the method is defined.</p>
|
|
|
<p>Finally, this pattern only supports single inheritance, and has no notion of
|
|
|
interfaces, class-based privacy, or other inheritance-related features. So, it
|
|
|
gives an experience that will be subtly surprising to programmers used to Java
|
|
|
inheritance, etc.</p>
|
|
|
<h2><a class="header" href="#discussion-15" id="discussion-15">Discussion</a></h2>
|
|
|
<p>There is no one good alternative. Depending on the exact circumstances it might
|
|
|
be better to re-implement using traits or to write out the facade methods to
|
|
|
dispatch to <code>Foo</code> manually. We do intend to add a mechanism for inheritance
|
|
|
similar to this to Rust, but it is likely to be some time before it reaches
|
|
|
stable Rust. See these <a href="http://aturon.github.io/blog/2015/09/18/reuse/">blog</a>
|
|
|
<a href="http://smallcultfollowing.com/babysteps/blog/2015/10/08/virtual-structs-part-4-extended-enums-and-thin-traits/">posts</a>
|
|
|
and this <a href="https://github.com/rust-lang/rfcs/issues/349">RFC issue</a> for more details.</p>
|
|
|
<p>The <code>Deref</code> trait is designed for the implementation of custom pointer types.
|
|
|
The intention is that it will take a pointer-to-<code>T</code> to a <code>T</code>, not convert
|
|
|
between different types. It is a shame that this isn't (probably cannot be)
|
|
|
enforced by the trait definition.</p>
|
|
|
<p>Rust tries to strike a careful balance between explicit and implicit mechanisms,
|
|
|
favouring explicit conversions between types. Automatic dereferencing in the dot
|
|
|
operator is a case where the ergonomics strongly favour an implicit mechanism,
|
|
|
but the intention is that this is limited to degrees of indirection, not
|
|
|
conversion between arbitrary types.</p>
|
|
|
<h2><a class="header" href="#see-also-19" id="see-also-19">See also</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="anti_patterns/../idioms/deref.html">Collections are smart pointers idiom</a>.</li>
|
|
|
<li>Delegation crates for less boilerplate like <a href="https://crates.io/crates/delegate">delegate</a>
|
|
|
or <a href="https://crates.io/crates/ambassador">ambassador</a></li>
|
|
|
<li><a href="https://doc.rust-lang.org/std/ops/trait.Deref.html">Documentation for <code>Deref</code> trait</a>.</li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#functional-usage-of-rust" id="functional-usage-of-rust">Functional Usage of Rust</a></h1>
|
|
|
<p>Rust is an imperative language, but it follows many
|
|
|
<a href="https://en.wikipedia.org/wiki/Functional_programming">functional programming</a> paradigms.</p>
|
|
|
<blockquote>
|
|
|
<p>In computer science, <em>functional programming</em> is a programming paradigm where
|
|
|
programs are constructed by applying and composing functions.
|
|
|
It is a declarative programming paradigm in which function definitions are
|
|
|
trees of expressions that each return a value, rather than a sequence of
|
|
|
imperative statements which change the state of the program.</p>
|
|
|
</blockquote>
|
|
|
<h1><a class="header" href="#programming-paradigms" id="programming-paradigms">Programming paradigms</a></h1>
|
|
|
<p>One of the biggest hurdles to understanding functional programs when coming
|
|
|
from an imperative background is the shift in thinking. Imperative programs
|
|
|
describe <strong>how</strong> to do something, whereas declarative programs describe
|
|
|
<strong>what</strong> to do. Let's sum the numbers from 1 to 10 to show this.</p>
|
|
|
<h2><a class="header" href="#imperative" id="imperative">Imperative</a></h2>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>let mut sum = 0;
|
|
|
for i in 1..11 {
|
|
|
sum += i;
|
|
|
}
|
|
|
println!("{}", sum);
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>With imperative programs, we have to play compiler to see what is happening.
|
|
|
Here, we start with a <code>sum</code> of <code>0</code>.
|
|
|
Next, we iterate through the range from 1 to 10.
|
|
|
Each time through the loop, we add the corresponding value in the range.
|
|
|
Then we print it out.</p>
|
|
|
<table><thead><tr><th align="center"><code>i</code></th><th align="center"><code>sum</code></th></tr></thead><tbody>
|
|
|
<tr><td align="center">1</td><td align="center">1</td></tr>
|
|
|
<tr><td align="center">2</td><td align="center">3</td></tr>
|
|
|
<tr><td align="center">3</td><td align="center">6</td></tr>
|
|
|
<tr><td align="center">4</td><td align="center">10</td></tr>
|
|
|
<tr><td align="center">5</td><td align="center">15</td></tr>
|
|
|
<tr><td align="center">6</td><td align="center">21</td></tr>
|
|
|
<tr><td align="center">7</td><td align="center">28</td></tr>
|
|
|
<tr><td align="center">8</td><td align="center">36</td></tr>
|
|
|
<tr><td align="center">9</td><td align="center">45</td></tr>
|
|
|
<tr><td align="center">10</td><td align="center">55</td></tr>
|
|
|
</tbody></table>
|
|
|
<p>This is how most of us start out programming. We learn that a program is a set
|
|
|
of steps.</p>
|
|
|
<h2><a class="header" href="#declarative" id="declarative">Declarative</a></h2>
|
|
|
<pre><pre class="playground"><code class="language-rust edition2018">
|
|
|
<span class="boring">#![allow(unused)]
|
|
|
</span><span class="boring">fn main() {
|
|
|
</span>println!("{}", (1..11).fold(0, |a, b| a + b));
|
|
|
<span class="boring">}
|
|
|
</span></code></pre></pre>
|
|
|
<p>Whoa! This is really different! What's going on here?
|
|
|
Remember that with declarative programs we are describing <strong>what</strong> to do,
|
|
|
rather than <strong>how</strong> to do it. <code>fold</code> is a function that <a href="https://en.wikipedia.org/wiki/Function_composition">composes</a>
|
|
|
functions. The name is a convention from Haskell.</p>
|
|
|
<p>Here, we are composing functions of addition (this closure: <code>|a, b| a + b</code>)
|
|
|
with a range from 1 to 10. The <code>0</code> is the starting point, so <code>a</code> is <code>0</code> at
|
|
|
first. <code>b</code> is the first element of the range, <code>1</code>. <code>0 + 1 = 1</code> is the result.
|
|
|
So now we <code>fold</code> again, with <code>a = 1</code>, <code>b = 2</code> and so <code>1 + 2 = 3</code> is the next
|
|
|
result. This process continues until we get to the last element in the range,
|
|
|
<code>10</code>.</p>
|
|
|
<table><thead><tr><th align="center"><code>a</code></th><th align="center"><code>b</code></th><th align="center">result</th></tr></thead><tbody>
|
|
|
<tr><td align="center">0</td><td align="center">1</td><td align="center">1</td></tr>
|
|
|
<tr><td align="center">1</td><td align="center">2</td><td align="center">3</td></tr>
|
|
|
<tr><td align="center">3</td><td align="center">3</td><td align="center">6</td></tr>
|
|
|
<tr><td align="center">6</td><td align="center">4</td><td align="center">10</td></tr>
|
|
|
<tr><td align="center">10</td><td align="center">5</td><td align="center">15</td></tr>
|
|
|
<tr><td align="center">15</td><td align="center">6</td><td align="center">21</td></tr>
|
|
|
<tr><td align="center">21</td><td align="center">7</td><td align="center">28</td></tr>
|
|
|
<tr><td align="center">28</td><td align="center">8</td><td align="center">36</td></tr>
|
|
|
<tr><td align="center">36</td><td align="center">9</td><td align="center">45</td></tr>
|
|
|
<tr><td align="center">45</td><td align="center">10</td><td align="center">55</td></tr>
|
|
|
</tbody></table>
|
|
|
<h1><a class="header" href="#additional-resources" id="additional-resources">Additional resources</a></h1>
|
|
|
<p>A collection of complementary helpful content</p>
|
|
|
<h2><a class="header" href="#talks" id="talks">Talks</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://www.youtube.com/watch?v=Pm_oO0N5B9k">Design Patterns in Rust</a> by
|
|
|
Nicholas Cameron at the PDRust (2016)</li>
|
|
|
<li><a href="https://www.youtube.com/watch?v=0zOg8_B71gE">Writing Idiomatic Libraries in Rust</a>
|
|
|
by Pascal Hertleif at RustFest (2017)</li>
|
|
|
<li><a href="https://www.youtube.com/watch?v=vqavdUGKeb4">Rust Programming Techniques</a> by
|
|
|
Nicholas Cameron at LinuxConfAu (2018)</li>
|
|
|
</ul>
|
|
|
<h2><a class="header" href="#books-online" id="books-online">Books (Online)</a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://rust-lang.github.io/api-guidelines">The Rust API Guidelines</a></li>
|
|
|
</ul>
|
|
|
<h1><a class="header" href="#design-principles" id="design-principles">Design principles</a></h1>
|
|
|
<h2><a class="header" href="#a-brief-overview-over-common-design-principles" id="a-brief-overview-over-common-design-principles">A brief overview over common design principles</a></h2>
|
|
|
<hr />
|
|
|
<h2><a class="header" href="#a-hrefhttpsenwikipediaorgwikisolidsolida" id="a-hrefhttpsenwikipediaorgwikisolidsolida"><a href="https://en.wikipedia.org/wiki/SOLID">SOLID</a></a></h2>
|
|
|
<ul>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Single-responsibility_principle">Single Responsibility Principle (SRP)</a>:
|
|
|
A class should only have a single responsibility, that is, only changes to
|
|
|
one part of the software's specification should be able to affect the
|
|
|
specification of the class.</li>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle">Open/Closed Principle (OCP)</a>:
|
|
|
"Software entities ... should be open for extension, but closed for
|
|
|
modification."</li>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle">Liskov Substitution Principle (LSP)</a>:
|
|
|
"Objects in a program should be replaceable with instances of their subtypes
|
|
|
without altering the correctness of that program."</li>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Interface_segregation_principle">Interface Segregation Principle (ISP)</a>:
|
|
|
"Many client-specific interfaces are better than one general-purpose
|
|
|
interface."</li>
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion Principle (DIP)</a>:
|
|
|
One should "depend upon abstractions, [not] concretions."</li>
|
|
|
</ul>
|
|
|
<h2><a class="header" href="#a-hrefhttpsenwikipediaorgwikidon27t_repeat_yourselfdry-dont-repeat-yourselfa" id="a-hrefhttpsenwikipediaorgwikidon27t_repeat_yourselfdry-dont-repeat-yourselfa"><a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY (Don’t Repeat Yourself)</a></a></h2>
|
|
|
<p>"Every piece of knowledge must have a single, unambiguous, authoritative
|
|
|
representation within a system"</p>
|
|
|
<h2><a class="header" href="#a-hrefhttpsenwikipediaorgwikikiss_principlekiss-principlea" id="a-hrefhttpsenwikipediaorgwikikiss_principlekiss-principlea"><a href="https://en.wikipedia.org/wiki/KISS_principle">KISS principle</a></a></h2>
|
|
|
<p>most systems work best if they are kept simple rather than made complicated;
|
|
|
therefore, simplicity should be a key goal in design, and unnecessary
|
|
|
complexity should be avoided</p>
|
|
|
<h2><a class="header" href="#a-hrefhttpsenwikipediaorgwikilaw_of_demeterlaw-of-demeter-loda" id="a-hrefhttpsenwikipediaorgwikilaw_of_demeterlaw-of-demeter-loda"><a href="https://en.wikipedia.org/wiki/Law_of_Demeter">Law of Demeter (LoD)</a></a></h2>
|
|
|
<p>a given object should assume as little as possible about the structure or
|
|
|
properties of anything else (including its subcomponents), in accordance with
|
|
|
the principle of "information hiding"</p>
|
|
|
<h2><a class="header" href="#a-hrefhttpsenwikipediaorgwikidesign_by_contractdesign-by-contract-dbca" id="a-hrefhttpsenwikipediaorgwikidesign_by_contractdesign-by-contract-dbca"><a href="https://en.wikipedia.org/wiki/Design_by_contract">Design by contract (DbC)</a></a></h2>
|
|
|
<p>software designers should define formal, precise and verifiable interface
|
|
|
specifications for software components, which extend the ordinary definition of
|
|
|
abstract data types with preconditions, postconditions and invariants</p>
|
|
|
<h2><a class="header" href="#a-hrefhttpsenwikipediaorgwikiencapsulation_computer_programmingencapsulationa" id="a-hrefhttpsenwikipediaorgwikiencapsulation_computer_programmingencapsulationa"><a href="https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)">Encapsulation</a></a></h2>
|
|
|
<p>bundling of data with the methods that operate on that data, or the restricting
|
|
|
of direct access to some of an object's components. Encapsulation is used to
|
|
|
hide the values or state of a structured data object inside a class, preventing
|
|
|
unauthorized parties' direct access to them.</p>
|
|
|
<h2><a class="header" href="#a-hrefhttpsenwikipediaorgwikicommande28093query_separationcommand-query-separationcqsa" id="a-hrefhttpsenwikipediaorgwikicommande28093query_separationcommand-query-separationcqsa"><a href="https://en.wikipedia.org/wiki/Command%E2%80%93query_separation">Command-Query-Separation(CQS)</a></a></h2>
|
|
|
<p>“Functions should not produce abstract side effects...only commands
|
|
|
(procedures) will be permitted to produce side effects.” - Bertrand Meyer:
|
|
|
Object Oriented Software Construction</p>
|
|
|
<h2><a class="header" href="#a-hrefhttpsenwikipediaorgwikiprinciple_of_least_astonishmentprinciple-of-least-astonishment-polaa" id="a-hrefhttpsenwikipediaorgwikiprinciple_of_least_astonishmentprinciple-of-least-astonishment-polaa"><a href="https://en.wikipedia.org/wiki/Principle_of_least_astonishment">Principle of least astonishment (POLA)</a></a></h2>
|
|
|
<p>a component of a system should behave in a way that most users will expect it
|
|
|
to behave. The behavior should not astonish or surprise users</p>
|
|
|
<h2><a class="header" href="#linguistic-modular-units" id="linguistic-modular-units">Linguistic-Modular-Units</a></h2>
|
|
|
<p>“Modules must correspond to syntactic units in the language used.” - Bertrand
|
|
|
Meyer: Object Oriented Software Construction</p>
|
|
|
<h2><a class="header" href="#self-documentation" id="self-documentation">Self-Documentation</a></h2>
|
|
|
<p>“The designer of a module should strive to make all information about the
|
|
|
module part of the module itself.” - Bertrand Meyer: Object Oriented Software
|
|
|
Construction</p>
|
|
|
<h2><a class="header" href="#uniform-access" id="uniform-access">Uniform-Access</a></h2>
|
|
|
<p>“All services offered by a module should be available through a uniform
|
|
|
notation, which does not betray whether they are implemented through storage or
|
|
|
through computation.” - Bertrand Meyer: Object Oriented Software Construction</p>
|
|
|
<h2><a class="header" href="#single-choice" id="single-choice">Single-Choice</a></h2>
|
|
|
<p>“Whenever a software system must support a set of alternatives, one and only
|
|
|
one module in the system should know their exhaustive list.” - Bertrand Meyer:
|
|
|
Object Oriented Software Construction</p>
|
|
|
<h2><a class="header" href="#persistence-closure" id="persistence-closure">Persistence-Closure</a></h2>
|
|
|
<p>“Whenever a storage mechanism stores an object, it must store with it the
|
|
|
dependents of that object. Whenever a retrieval mechanism retrieves a
|
|
|
previously stored object, it must also retrieve any dependent of that object
|
|
|
that has not yet been retrieved.” - Bertrand Meyer: Object Oriented Software
|
|
|
Construction</p>
|
|
|
|
|
|
</main>
|
|
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
|
<!-- Mobile navigation buttons -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div style="clear: both"></div>
|
|
|
</nav>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
|
|
|
|
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
|
window.playground_copyable = true;
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
|
|
|
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
|
|
|
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
|
|
|
|
|
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
|
|
|
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
|
|
|
<script src="book.js" type="text/javascript" charset="utf-8"></script>
|
|
|
|
|
|
<!-- Custom JS scripts -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
|
window.addEventListener('load', function() {
|
|
|
window.setTimeout(window.print, 100);
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
</body>
|
|
|
</html>
|