<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="description" content="
"/>
<meta name="keywords" content=" "/>
<style type="text/css">
.underline { text-decoration: underline; }
</style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js/dist/reveal.css"/>

<link rel="stylesheet" href="./etc/my_theme.css" id="theme"/>

<link rel="stylesheet" href="./etc/operandi-tinted.css"/>

<link rel="stylesheet" href="./etc/footer.css"/>

<link rel="stylesheet" type="text/css" href="./etc/operandi-tinted.css" />
</head>
<body>
<div class="reveal">
<div class="slides">

<section>
<section id="slide-orgba7e0bb">
<h2 id="orgba7e0bb">views::maybe and views::nullable</h2>
<p>
Steve Downey
</p>




</section>
</section>
<section>
<section id="slide-org40ee6e6">
<h2 id="org40ee6e6">Abstract</h2>
<p>
Two new views of zero or one element
</p>

<dl>
<dt><code>views::nullable</code></dt><dd>an adaptor over a <code>nullable</code></dd>
<dt><code>views::maybe</code></dt><dd>an owning view of zero or one elements</dd>

</dl>


<aside class="notes">
<p>

</p>

</aside>

</section>
</section>
<section>
<section id="slide-org38c7aea">
<h2 id="org38c7aea"><code>nullable</code></h2>
<ol>
<li>Contextually convertable to <code>bool</code></li>
<li><p>
Dereferenceable
</p>

<p>
Things like pointers, std::optional, std::expected
</p></li>

</ol>

</section>
</section>
<section>
<section id="slide-org3af1ad7">
<h3 id="org3af1ad7">Unsafe at any speed</h3>
<p>
Only safely dereferenceable if <b>truthy</b>
</p>

</section>
</section>
<section>
<section id="slide-orgf937c6c">
<h2 id="orgf937c6c"><code>views::nullable</code></h2>
<p>
Adapt a nullable by lifting from the nullable monad to the ranges monad.
</p>

<p>
(you can safely ignore the M-word)
</p>

</section>
</section>
<section>
<section id="slide-org1af1db3">
<h3 id="org1af1db3">Example</h3>
<ul>
<li>Before</li>

</ul>
<div class="org-src-container">

<pre class="src src-c++"><span class="org-keyword">auto</span> <span class="org-variable-name">opt</span> = possible_value();
<span class="org-keyword">if</span> (opt) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">a few dozen lines ...</span>
    use(*opt); <span class="org-comment-delimiter">// </span><span class="org-comment">is *opt Safe ?</span>
}
</pre>
</div>
<ul>
<li>After</li>

</ul>
<div class="org-src-container">

<pre class="src src-c++"><span class="org-keyword">for</span> (<span class="org-keyword">auto</span>&amp;&amp; <span class="org-variable-name">opt</span> : <span class="org-constant">views</span>::nullable(possible_value())) {
    <span class="org-comment-delimiter">// </span><span class="org-comment">a few dozen lines ...</span>
    use(opt); <span class="org-comment-delimiter">// </span><span class="org-comment">opt is Safe</span>
}
</pre>
</div>

<aside class="notes">
<p>
You get used to iterating over zero or one
</p>

</aside>


</section>
</section>
<section>
<section id="slide-org42ddf90">
<h2 id="org42ddf90"><code>views::maybe</code></h2>
<p>
A <code>range</code> of zero or one elements
</p>

<p>
A view the same way <code>views::single</code> is
</p>

<p>
&#x2013;
</p>

<p>
O(1) with large C
</p>

</section>
</section>
<section>
<section id="slide-org09b6262">
<h3 id="org09b6262">Example</h3>
<p>
Shows up in range comprehensions for guard clauses
</p>
<div class="org-src-container">

<pre class="src src-haskell">[ (x, y, z) <span class="org-haskell-operator">|</span> z <span class="org-haskell-operator">&lt;-</span> [1<span class="org-haskell-operator">..</span>], y <span class="org-haskell-operator">&lt;-</span> [1<span class="org-haskell-operator">..</span>z], x <span class="org-haskell-operator">&lt;-</span> [1<span class="org-haskell-operator">..</span>y], x<span class="org-haskell-operator">^</span>2 <span class="org-haskell-operator">+</span> y<span class="org-haskell-operator">^</span>2 <span class="org-haskell-operator">==</span> z<span class="org-haskell-operator">^</span>2]
</pre>
</div>
</section>
<section id="slide-orgfc2a586">
<h5 id="orgfc2a586"><code>yield_if</code></h5>
<div class="org-src-container">

<pre class="src src-c++"><span class="org-keyword">inline</span> <span class="org-keyword">constexpr</span> <span class="org-keyword">auto</span> <span class="org-variable-name">yield_if</span> = [](<span class="org-type">bool</span> <span class="org-variable-name">b</span>, <span class="org-keyword">auto</span> <span class="org-variable-name">x</span>) {
    <span class="org-keyword">return</span> b ? maybe_view{<span class="org-constant">std</span>::move(x)} : <span class="org-type">maybe_view</span>&lt;<span class="org-keyword">decltype</span>(x)&gt;{};
};
</pre>
</div>
</section>
<section id="slide-orgdf16a1b">
<h5 id="orgdf16a1b"><code>and_then</code></h5>
<div class="org-src-container">

<pre class="src src-c++"><span class="org-keyword">inline</span> <span class="org-keyword">constexpr</span> <span class="org-keyword">auto</span> <span class="org-variable-name">and_then</span> = [](<span class="org-keyword">auto</span>&amp;&amp; <span class="org-variable-name">r</span>, <span class="org-keyword">auto</span> <span class="org-variable-name">fun</span>) {
  <span class="org-keyword">return</span> <span class="org-keyword">decltype</span>(r)(r)
         | <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-constant">views</span>::transform(<span class="org-constant">std</span>::move(fun))
         | <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-constant">views</span>::join;
};
</pre>
</div>
</section>
<section id="slide-orgdd1c061">
<h5 id="orgdd1c061">Desugared Comprehension</h5>
<div class="org-src-container">

<pre class="src src-c++">    <span class="org-keyword">using</span> <span class="org-constant">std</span>::<span class="org-constant">ranges</span>::<span class="org-constant">views</span>::<span class="org-constant">iota</span>;
    <span class="org-keyword">auto</span> <span class="org-variable-name">triples</span> = and_then(iota(1), [](<span class="org-type">int</span> <span class="org-variable-name">z</span>) {
        <span class="org-keyword">return</span> and_then(iota(1, z + 1), [=](<span class="org-type">int</span> <span class="org-variable-name">x</span>) {
            <span class="org-keyword">return</span> and_then(iota(x, z + 1), [=](<span class="org-type">int</span> <span class="org-variable-name">y</span>) {
                <span class="org-keyword">return</span> yield_if(x * x + y * y == z * z,
                                <span class="org-constant">std</span>::make_tuple(x, y, z));
            });
        });
    });
</pre>
</div>
</section>
</section>
<section>
<section id="slide-orga70235d">
<h3 id="orga70235d">Similar to <code>filter</code></h3>
<p>
Flattening a range of ranges excluding the empty range operates much like filter.
</p>

<p>
Different trade-offs.
</p>

<p>
Easier if the condition is not a simple property of the element.
</p>

<p>
The standard library should not be overly opinionated.
</p>

</section>
</section>
<section>
<section id="slide-orgc8ed567">
<h3 id="orgc8ed567">Vocabulary</h3>
<p>
Useful as a return type for range code.
</p>

<p>
Provide fit and a polish
</p>
<ul>
<li>Monadic Ops</li>
<li>T&amp;
<ul>
<li>No assignment from T</li>
<li>views::maybe never deduces a ref</li>

</ul></li>

</ul>

</section>
</section>
<section>
<section id="slide-org63f2223">
<h3 id="org63f2223">Differences from Optional</h3>
<p>
Is a range
</p>

<p>
Does not support assignment from underlying
</p>


</section>
</section>
<section>
<section id="slide-orgc0ef2c9">
<h3 id="orgc0ef2c9">Support for T&amp;</h3>
<p>
Because there is no assignment from T there is no question about rebind/assign-through.
</p>

<p>
Assignment from views::maybe&lt;T&amp;&gt; rebinds, preserving equality behavior.
</p>

</section>
</section>
<section>
<section id="slide-orgcb0616a">
<h3 id="orgcb0616a">Support for std::reference_wrapper</h3>
<p>
There is specialized support for eliding the <code>get</code> operation to make a maybe&lt;std::reference_wrapper&lt;T&gt;&gt; work directly.
</p>

<p>
If T&amp; specialization is in place, it should be dropped and the disjucntion in the concept removed.
</p>

</section>
</section>
<section>
<section id="slide-org44c77cb">
<h2 id="org44c77cb">Examples From Test Cases</h2>
<div class="outline-text-2" id="text-org44c77cb">
</div>
</section>
</section>
<section>
<section id="slide-org61d628f">
<h3 id="org61d628f">Basic maybe&lt;int&gt;</h3>
<div class="org-src-container">

<pre class="src src-c++">    <span class="org-type">int</span>             <span class="org-variable-name">i</span> = 7;
    <span class="org-type">maybe_view</span>&lt;<span class="org-type">int</span>&gt; <span class="org-variable-name">v1</span>{};
    ASSERT_TRUE(v1.size() == 0);

    <span class="org-type">maybe_view</span>&lt;<span class="org-type">int</span>&gt; <span class="org-variable-name">v2</span>{i};
    ASSERT_TRUE(v2.size() == 1);
    <span class="org-keyword">for</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">i</span> : v1)
        ASSERT_TRUE(i != i); <span class="org-comment-delimiter">// </span><span class="org-comment">tautology so i is used and not warned</span>

    <span class="org-keyword">for</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">i</span> : v2)
        ASSERT_EQ(i, 7);

    <span class="org-type">int</span> <span class="org-variable-name">s</span> = 4;
    <span class="org-keyword">for</span> (<span class="org-keyword">auto</span>&amp;&amp; <span class="org-variable-name">i</span> : <span class="org-constant">views</span>::maybe(s)) {
        ASSERT_EQ(i, 4);
        i = 9;
        ASSERT_EQ(i, 9);
    }
    ASSERT_EQ(s, 4);
</pre>
</div>
</section>
</section>
<section>
<section id="slide-orgaa3795a">
<h3 id="orgaa3795a">Basic maybe&lt;reference_wrapper&lt;int&gt;&gt;</h3>
<div class="org-src-container">

<pre class="src src-c++">    <span class="org-type">int</span> <span class="org-variable-name">i</span> = 7;

    <span class="org-type">maybe_view</span>&lt;<span class="org-type">int</span>&gt; <span class="org-variable-name">v2</span>{<span class="org-constant">std</span>::ref(i)};

    <span class="org-keyword">for</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">i</span> : v2)
        ASSERT_EQ(i, 7);

    <span class="org-type">int</span> <span class="org-variable-name">s</span> = 4;
    <span class="org-keyword">for</span> (<span class="org-keyword">auto</span>&amp;&amp; <span class="org-variable-name">i</span> : <span class="org-constant">views</span>::maybe(<span class="org-constant">std</span>::ref(s))) {
        ASSERT_EQ(i, 4);
        i.get() = 9;
        ASSERT_EQ(i, 9);
    }
    ASSERT_EQ(s, 9);
</pre>
</div>
</section>
</section>
<section>
<section id="slide-org68e917e">
<h3 id="org68e917e">Basic Nullable</h3>
<div class="org-src-container">

<pre class="src src-c++">    <span class="org-constant">std</span>::<span class="org-type">optional</span>      <span class="org-variable-name">s</span>{7};

    <span class="org-keyword">for</span> (<span class="org-keyword">auto</span> <span class="org-variable-name">i</span> : <span class="org-constant">views</span>::nullable(s))
        ASSERT_EQ(i, 7);

    <span class="org-type">nullable_view</span> <span class="org-variable-name">e</span>{<span class="org-constant">std</span>::<span class="org-type">optional</span>&lt;<span class="org-type">int</span>&gt;{}};
    <span class="org-keyword">for</span> (<span class="org-type">int</span> <span class="org-variable-name">i</span> : e)
        ASSERT_TRUE(i != i);

</pre>
</div>
</section>
</section>
<section>
<section id="slide-org10c64ae">
<h2 id="org10c64ae">Thank You</h2>
<aside class="notes">
<p>

</p>

</aside>
</section>
</section>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/reveal.js/dist/reveal.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js/plugin/markdown/markdown.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js/plugin/notes/notes.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js/plugin/search/search.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js/plugin/zoom/zoom.js"></script>
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({

controls: true,
progress: true,
history: false,
center: true,
slideNumber: 'c',
rollingLinks: false,
keyboard: true,
mouseWheel: false,
fragmentInURL: false,
hashOneBasedIndex: false,
pdfSeparateFragments: true,
overview: true,
width: 1600,
height: 900,

transition: 'fade',
transitionSpeed: 'default',
showNotes: window.location.search.match( /print-pdf/gi ) ? 'separate-page' : false,

// Plugins with reveal.js 4.x
plugins: [ RevealMarkdown, RevealNotes, RevealSearch, RevealZoom ],

// Optional libraries used to extend reveal.js
dependencies: [
]

});
</script>
</body>
</html>
