1<?xml version="1.0" encoding="UTF-8"?> 2<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" 3"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"> 4<section id="safe_numerics.rationale"> 5 <title>Rationale and FAQ</title> 6 7 <qandaset defaultlabel="number"> 8 <qandaentry> 9 <question> 10 <para>Is this really necessary? If I'm writing the program with the 11 requisite care and competence, problems noted in the introduction will 12 never arise. Should they arise, they should be fixed "at the source" 13 and not with a "band aid" to cover up bad practice.</para> 14 </question> 15 16 <answer> 17 <para>This surprised me when it was first raised. But some of the 18 feedback I've received makes me think that it's a widely held view. 19 The best answer is to consider the examples in the <link 20 linkend="safe_numerics.tutorial">Tutorials and Motivating 21 Examples</link> section of the library documentation. I believe they 22 convincingly demonstrate that any program which does not use this 23 library must be assumed to contain arithmetic errors.</para> 24 </answer> 25 </qandaentry> 26 27 <qandaentry> 28 <question> 29 <para>Can safe types be used as drop-in replacements for built-in 30 types?</para> 31 </question> 32 33 <answer> 34 <para>Almost. Replacing all built-in types with their safe 35 counterparts should result in a program that will compile and run as 36 expected. Occasionally compile time errors will occur and adjustments 37 to the source code will be required. Typically these will result in 38 code which is more correct.</para> 39 </answer> 40 </qandaentry> 41 42 <qandaentry> 43 <question> 44 <para>Why are there special types for literal such as 45 <code>safe_signed_literal<42></code>? Why not just use 46 std::integral_const<int, 42>?</para> 47 </question> 48 49 <answer> 50 <para>By defining our own "special" type we can simplify the 51 interface. Using <code>std::integral_const</code> requires one to 52 specify both the type <emphasis>and</emphasis> the value. Using 53 <code>safe_signed_literal<42></code> doesn't require a parameter 54 for the type. So the library can select the best type to hold the 55 specified value. It also means that one won't have the opportunity to 56 specify a type-value pair which are inconsistent.</para> 57 </answer> 58 </qandaentry> 59 60 <qandaentry> 61 <question> 62 <para>Why is safe...literal needed at all? What's the matter with 63 <code>const safe<int>(42)</code>?</para> 64 </question> 65 66 <answer> 67 <para><code>const safe<int>(42)</code> looks like it might be 68 what we want: An immutable value which invokes the "safe" operators 69 when used in an expression. But there is one problem. The 70 <code>std::numeric_limits<safe<int>></code> is a range 71 from INTMIN to INTMAX even though the value is fixed to 42 at compile 72 time. It is this range which is used at compile time to calculate the 73 range of the result of the operation.</para> 74 75 <para>So when an operation is performed, the range of the result is 76 calculated from [INTMIN, INTMAX] rather than from [42,42].</para> 77 </answer> 78 </qandaentry> 79 80 <qandaentry> 81 <question> 82 <para>Are safe type operations <code>constexpr</code>? That is, can 83 they be invoked at compile time?</para> 84 </question> 85 86 <answer> 87 <para>Yes. safe type construction and calculations are all 88 <code>constexpr</code>. Note that to get maximum benefit, you'll have 89 to use <code>safe...literal</code> to specify the primitive values at 90 compile time.</para> 91 </answer> 92 </qandaentry> 93 94 <qandaentry> 95 <question> 96 <para>Why define <link 97 linkend="safe_numerics.safe_literal"><code>safe_literal</code></link>? 98 Isn't it effectively the same as 99 <code>std::integral_constant</code>?</para> 100 </question> 101 102 <answer> 103 <para>Almost, but there are still good reasons to create a different 104 type.<itemizedlist> 105 <listitem> 106 <para><code>std::integral_constant<int, 42></code> 107 requires specification of type as well as value so it's less 108 convenient than safe_signed_literal which maps to the smallest 109 type required to hold the value.</para> 110 </listitem> 111 112 <listitem> 113 <para><code>std::numeric_limits<std::integral_constant<int, 114 42>>::is_integer</code> returns <code>false</code>. This 115 would complicate implementation of the library</para> 116 </listitem> 117 118 <listitem> 119 <para>type trait <code>is_safe<std::integral_constant<int, 120 42>></code> would have to be defined to return 121 <code>true</code>.</para> 122 </listitem> 123 124 <listitem> 125 <para>But globally altering the traits of 126 <code>std::integral_constant</code> might have unintended 127 side-effects related to other code. These might well be 128 surprises which are create errors which are hard to find and 129 hard to work around.</para> 130 </listitem> 131 </itemizedlist></para> 132 </answer> 133 </qandaentry> 134 135 <qandaentry> 136 <question> 137 <para>Why is Boost.Convert not used?</para> 138 </question> 139 140 <answer> 141 <para>I couldn't figure out how to use it from the 142 documentation.</para> 143 </answer> 144 </qandaentry> 145 146 <qandaentry> 147 <question> 148 <para>Why is the library named "safe ..." rather than something like 149 "checked ..." ?</para> 150 </question> 151 152 <answer> 153 <para>I used "safe" in large part because this is what has been used 154 by other similar libraries. Maybe a better word might have been 155 "correct" but that would raise similar concerns. I'm not inclined to 156 change this. I've tried to make it clear in the documentation what the 157 problem that the library addressed is.</para> 158 </answer> 159 </qandaentry> 160 161 <qandaentry> 162 <question> 163 <para>Given that the library is called "numerics" why is floating 164 point arithmetic not addressed?</para> 165 </question> 166 167 <answer> 168 <para>Actually, I believe that this can/should be applied to any type 169 T which satisfies the type requirement <code>Numeric</code> type as 170 defined in the documentation. So there should be specializations 171 <code>safe<float></code> and related types as well as new types 172 like <code>safe<fixed_decimal></code> etc. But the current 173 version of the library only addresses integer types. Hopefully the 174 library will evolve to match the promise implied by its name.</para> 175 </answer> 176 </qandaentry> 177 178 <qandaentry> 179 <question> 180 <para>Isn't putting a defensive check just before any potential 181 undefined behavior often considered a bad practice?</para> 182 </question> 183 184 <answer> 185 <para>By whom? Is leaving code which can produce incorrect results 186 better? Note that the documentation contains references to various 187 sources which recommend exactly this approach to mitigate the problems 188 created by this C/C++ behavior. See 189 <citation>Seacord</citation></para> 190 </answer> 191 </qandaentry> 192 193 <qandaentry> 194 <question> 195 <para>It looks like the implementation presumes two's complement 196 arithmetic at the hardware level. So this library is not portable - 197 correct? What about other hardware architectures?</para> 198 </question> 199 200 <answer> 201 <para>As far as is known as of this writing, the library does not 202 presume that the underlying hardware is two's complement. However, 203 this has yet to be verified in any rigorous way.</para> 204 </answer> 205 </qandaentry> 206 207 <qandaentry> 208 <question> 209 <para>According to C/C++ standards, <code>unsigned integers</code> 210 cannot overflow - they are modular integers which "wrap around". Yet 211 the safe numerics library detects and traps this behavior as errors. 212 Why is that?</para> 213 </question> 214 215 <answer> 216 <para>The guiding purpose of the library is to trap incorrect 217 arithmetic behavior - not just undefined behavior. Although a savvy 218 user may understand and keep present in his mind that an unsigned 219 integer is really a modular type, the plain reading of an arithmetic 220 expression conveys the idea that all operands are common integers. 221 Also in many cases, <code>unsigned integers</code> are used in cases 222 where modular arithmetic is not intended, such as array indices. 223 Finally, the modulus for such an integer would vary depending upon the 224 machine architecture. For these reasons, in the context of this 225 library, an <code>unsigned integer</code> is considered to be a 226 representation of a subset of integers. Note that this decision is 227 consistent with <citation>INT30-C</citation>, “Ensure that unsigned 228 integer operations do not wrap” in the CERT C Secure Coding Standard 229 <citation>Seacord</citation>.</para> 230 </answer> 231 </qandaentry> 232 233 <qandaentry> 234 <question> 235 <para>Why does the library require C++14?</para> 236 </question> 237 238 <answer> 239 <para>The original version of the library used C++11. Feedback from 240 CPPCon, <ulink url="http://www.blincubator.com">Boost Library 241 Incubator</ulink> and Boost developer's mailing list convinced me that 242 I had to address the issue of run-time penalty much more seriously. I 243 resolved to eliminate or minimize it. This led to more elaborate 244 meta-programming. But this wasn't enough. It became apparent that the 245 only way to really minimize run-time penalty was to implement 246 compile-time integer range arithmetic - a pretty elaborate sub 247 library. By doing range arithmetic at compile-time, I could skip 248 runtime checking on many/most integer operations. While C++11 249 <code>constexpr</code> wasn't quite powerful enough to do the job, 250 C++14 <code>constexpr</code> is. The library currently relies very 251 heavily on C++14 <code>constexpr</code>. I think that those who delve 252 into the library will be very surprised at the extent that minor 253 changes in user code can produce guaranteed correct integer code with 254 zero run-time penalty.</para> 255 </answer> 256 </qandaentry> 257 258 <qandaentry> 259 <question> 260 <para>This is a C++ library - yet you refer to C/C++. Which is 261 it?</para> 262 </question> 263 264 <answer> 265 <para>C++ has evolved way beyond the original C language. But C++ is 266 still (mostly) compatible with C. So most C programs can be compiled 267 with a C++ compiler. The problems of incorrect arithmetic afflict both 268 C and C++. Suppose we have a legacy C program designed for some 269 embedded system.<itemizedlist> 270 <listitem> 271 <para>Replace all <code>int</code> declarations with 272 <code>int16_t</code> and all <code>long</code> declarations with 273 <code>int32_t</code>.</para> 274 </listitem> 275 276 <listitem> 277 <para>Create a file containing something like the following and 278 include it at the beginning of every source file.</para> 279 280 <programlisting>#ifdef TEST 281// using C++ on test platform 282#include <cstdint> 283#include <boost/numeric/safe_numerics/safe_integer.hpp> 284#include <cpp.hpp> 285using pic16_promotion = boost::numeric::cpp< 286 8, // char 287 8, // short 288 8, // int 289 16, // long 290 32 // long long 291>; 292// define safe types used in the desktop version of the program. 293template <typename T> // T is char, int, etc data type 294using safe_t = boost::numeric::safe< 295 T, 296 pic16_promotion, 297 boost::numeric::default_exception_policy // use for compiling and running tests 298>; 299typedef safe_t<std::int_least16_t> int16_t; 300typedef safe_t<std::int_least32_t> int32_t; 301#else 302/* using C on embedded platform */ 303typedef int int_least16_t; 304typedef long int_least16_t; 305#endif 306 307</programlisting> 308 </listitem> 309 310 <listitem> 311 <para>Compile tests on the desktop with a C++14 compiler and 312 with the macro TEST defined.</para> 313 </listitem> 314 315 <listitem> 316 <para>Run the tests and change the code to address any thrown 317 exceptions.</para> 318 </listitem> 319 320 <listitem> 321 <para>Compile for the target C platform with the macro TEST 322 undefined.</para> 323 </listitem> 324 </itemizedlist></para> 325 326 <para>This example illustrates how this library, implemented with 327 C++14 can be useful in the development of correct code for programs 328 written in C.</para> 329 </answer> 330 </qandaentry> 331 332 <qandaentry> 333 <question> 334 <para>Some compilers (including gcc and clang) include builtin 335 functions for checked addition, multiplication, etc. Does this library 336 use these intrinsics?</para> 337 </question> 338 339 <answer> 340 <para>No. I attempted to use these but they are currently not 341 <code>constexpr</code>. So I couldn't use these without breaking 342 <code>constexpr</code> compatibility for the safe numerics 343 primitives.</para> 344 </answer> 345 </qandaentry> 346 347 <qandaentry> 348 <question> 349 <para>Some compilers (including gcc and clang) included a builtin 350 function for detecting constants. This seemed attractive to eliminate 351 the requirement for the safe_literal type. Alas, these builtin 352 functions are defined as macros. Constants passed through functions 353 down into the safe numerics library cannot be detected as constants. 354 So the opportunity to make the library even more efficient by moving 355 more operations to compile time doesn't exist - contrary to my hopes 356 and expections.</para> 357 </question> 358 </qandaentry> 359 </qandaset> 360</section> 361