2
0
mirror of https://github.com/boostorg/convert.git synced 2026-01-26 18:32:56 +00:00
Files
convert/doc/html/boost_convert/design_notes/user_interface_signature.html
2022-04-15 07:12:24 +10:00

194 lines
22 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>User Interface Signature</title>
<link rel="stylesheet" href="../../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter 1. Boost.Convert 2.0">
<link rel="up" href="../design_notes.html" title="Design Notes">
<link rel="prev" href="converter_signature.html" title="Converter Signature">
<link rel="next" href="../supporting_tools.html" title="Supporting Tools">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="spirit-nav">
<a accesskey="p" href="converter_signature.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../design_notes.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="../supporting_tools.html"><img src="../../images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="boost_convert.design_notes.user_interface_signature"></a><a class="link" href="user_interface_signature.html" title="User Interface Signature">User
Interface Signature</a>
</h3></div></div></div>
<p>
The first attempt to accommodate the User Requirements might result in the
following fairly conventional interface:
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">&gt;</span> <span class="identifier">Out</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#1</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">&gt;</span> <span class="identifier">Out</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">fallback</span><span class="special">);</span> <span class="comment">//#2</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">&gt;</span> <span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">Out</span><span class="special">&amp;</span> <span class="identifier">result_out</span><span class="special">,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#3</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">&gt;</span> <span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">Out</span><span class="special">&amp;</span> <span class="identifier">result_out</span><span class="special">,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">fallback</span><span class="special">);</span> <span class="comment">//#4</span>
</pre>
<p>
with the following behavior:
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
returns the result or throws on failure (<span class="emphasis"><em>R3a</em></span>, <span class="emphasis"><em>R4</em></span>);
</li>
<li class="listitem">
does not throw, returns the result or the provided fallback (<span class="emphasis"><em>R3b</em></span>,
<span class="emphasis"><em>R5</em></span>, <span class="emphasis"><em>R5c</em></span> but not <span class="emphasis"><em>R5a</em></span>);
</li>
<li class="listitem">
does not throw, writes the result to <code class="computeroutput"><span class="identifier">result_out</span></code>
(when successful), returns indication of success or failure (<span class="emphasis"><em>R3b</em></span>,
<span class="emphasis"><em>R5</em></span>, <span class="emphasis"><em>R5a</em></span> but not <span class="emphasis"><em>R5c</em></span>);
</li>
<li class="listitem">
does not throw, writes the result to <code class="computeroutput"><span class="identifier">result_out</span></code>
(when successful) or the provided fallback, returns indication of success
or failure (<span class="emphasis"><em>R3b</em></span>, <span class="emphasis"><em>R5</em></span>, <span class="emphasis"><em>R5c</em></span>
and <span class="emphasis"><em>R5a</em></span>).
</li>
</ol></div>
<p>
The #3 and #4 signatures are special as they, in fact, return two things
-- the actual result (written into the <code class="computeroutput"><span class="identifier">result_out</span></code>)
and the indication of success or failure (returned by the functions). Given
that a reference to <code class="computeroutput"><span class="identifier">result_out</span></code>
is passed in, the actual <code class="computeroutput"><span class="identifier">result_out</span></code>
instance is constructed (storage allocated and initialized) outside the function
calls.
</p>
<p>
Similar to the scenario described in the <a class="link" href="converter_signature.html" title="Converter Signature">Converter
Signature</a> section that results in an additional and unnecessary overhead.
Indeed, if the conversion operation succeeds, then the initialization value
is overridden (with the actual result), if it fails, then the value is either
overridden still (with the fallback) or is meaningless.
</p>
<p>
To avoid the overhead we might again (as in the <a class="link" href="converter_signature.html" title="Converter Signature">Converter
Signature</a> section) deploy <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span></code>
and to change the signatures to
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;&amp;,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#3</span>
<span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;&amp;,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#4</span>
</pre>
<p>
Now, when we look at #3, we can see that the indication of success or failure
is duplicated. Namely, it is returned from the function and is encapsulated
in <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;</span></code>.
Consequently, #3 can be further simplified to
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;&amp;,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#3</span>
</pre>
<p>
or expressed more idiomatically (in C++) as:
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#3</span>
</pre>
<p>
So far, we have arrived to the following set
</p>
<pre class="programlisting"><span class="identifier">Out</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#1</span>
<span class="identifier">Out</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#2</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#3</span>
<span class="keyword">bool</span> <span class="identifier">convert</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;&amp;,</span> <span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&amp;);</span> <span class="comment">//#4</span>
</pre>
<p>
which as a whole looks quite ugly and, in fact, does not even compile as
#1 clashes with #3. The good thing though is that <span class="emphasis"><em>functionally</em></span>
#1 and #2 are not needed anymore as they are duplicates of the following
#3 deployments:
</p>
<pre class="programlisting"><span class="identifier">Out</span> <span class="identifier">out1</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">).</span><span class="identifier">value</span><span class="special">();</span> <span class="comment">// #3 with #1 behavior</span>
<span class="identifier">Out</span> <span class="identifier">out2</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">).</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback</span><span class="special">);</span> <span class="comment">// #3 with #2 behavior</span>
</pre>
<p>
Again, we are not discussing aesthetic aspects of the interface (or syntactic
sugar some might say, which might be very subjective). Instead, we are focusing
on the <span class="emphasis"><em>functional completeness</em></span> and so far we manage
to maintain the same <span class="emphasis"><em>functional completeness</em></span> with <span class="emphasis"><em>less</em></span>.
</p>
<p>
Turns out, with a bit of effort, we can get away without the most complex
one -- #4 -- as well:
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;</span> <span class="identifier">out</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="identifier">out_success</span> <span class="special">=</span> <span class="identifier">out</span> <span class="special">?</span> <span class="keyword">true</span> <span class="special">:</span> <span class="keyword">false</span><span class="special">;</span>
<span class="identifier">Out</span> <span class="identifier">out_value</span> <span class="special">=</span> <span class="identifier">out</span><span class="special">.</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback</span><span class="special">);</span>
</pre>
<p>
So, ultimately we arrive to one and only
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;);</span>
</pre>
<p>
The important qualities of the API are that it is <span class="emphasis"><em>functionally-complete</em></span>
and the <span class="emphasis"><em>most efficient way</em></span> to deploy the chosen converter
signature (see the <a class="link" href="converter_signature.html" title="Converter Signature">Converter
Signature</a> section). Namely, the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">()</span></code> interface is routinely optimized out (elided)
when deployed as
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="identifier">Out</span><span class="special">&gt;</span> <span class="identifier">out</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">);</span>
</pre>
<p>
The API has several deployment-related advantages. First, it says exactly
what it does. Given a conversion request is only a <span class="emphasis"><em>request</em></span>,
the API returns <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span></code> essentially saying "I'll
try but I might fail. Proceed as you find appropriate.". Honest and
simple. I prefer it to "I'll try. I might fail but you do not want to
know about it." or "I'll try. If I fail, you die." or variations
along these lines. :-)
</p>
<p>
On a more serious note though the interface allows for batched conveyor-style
conversions. Namely, attempting to convert several values, in sequence, storing
the <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span></code> results and, then, analyzing/validating
them (without losing the information if each individual conversion was successful
or not) in some semi-automated way.
</p>
<p>
Again, that API does not have to be the only API <span class="emphasis"><em>Boost.Convert</em></span>
provides. However, that API is the only <span class="emphasis"><em>essential</em></span> API.
Other APIs are relatively easily derived from it. For example,
</p>
<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Out</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">In</span><span class="special">&gt;</span>
<span class="identifier">Out</span>
<span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">in</span><span class="special">,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">fallback</span><span class="special">)</span> <span class="comment">//#2</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">in</span><span class="special">).</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
Given that it is extremely difficult (if not impossible) to come up with
a library API that could please everyone, we might as well settle on the
<span class="emphasis"><em>essential</em></span> API and let the users build their own APIs
(as in the example above) to satisfy their aesthetic preferences.
</p>
<p>
Still, it needs to be acknowledged that <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span></code>
is a fairly new concept and some people are reluctant using it or find its
deployment unreasonably complicating. Consequently, <span class="emphasis"><em>Boost.Convert</em></span>
provides an alternative (more conventional) interface:
</p>
<pre class="programlisting"><span class="identifier">Out</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Converter</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Out</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">fallback_value</span><span class="special">);</span>
<span class="identifier">Out</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Converter</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Functor</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">fallback_functor</span><span class="special">);</span>
<span class="identifier">Out</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">In</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">Converter</span> <span class="keyword">const</span><span class="special">&amp;,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">throw_on_failure</span><span class="special">);</span>
</pre>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright © 2009-2022 Vladimir
Batov<p>
Distributed under the Boost Software License, Version 1.0. See copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>.
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="converter_signature.html"><img src="../../images/prev.png" alt="Prev"></a><a accesskey="u" href="../design_notes.html"><img src="../../images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../images/home.png" alt="Home"></a><a accesskey="n" href="../supporting_tools.html"><img src="../../images/next.png" alt="Next"></a>
</div>
</body>
</html>