Free AI web copilot to create summaries, insights and extended knowledge, download it at here
3145
Abstract
ted to contemplate how you would solve this in your favorite (statically typed) language.</p><h2 id="2e29">Solution:</h2><p id="5c42">To solve our problem we will utilize Rust’s <code>Trait</code> system. The above situation is a very good example to remember for what reason traits do exist in Rust’s ecosystem.</p><p id="e7af">We define the following trait:</p><div id="d3b8"><pre><span class="hljs-keyword">pub</span> <span class="hljs-keyword">trait</span> <span class="hljs-title class_">Sin</span><T> {
<span class="hljs-keyword">fn</span> <span class="hljs-title function_">sin</span>(v: &<span class="hljs-type">Vec</span><T>) <span class="hljs-punctuation">-></span> <span class="hljs-type">Vec</span><T>;
}</pre></div><p id="95f5">This just replicates our method signature but using a generic type parameter <code>T</code>. But it provides much to our code: “Sine is now a trait”. Let us compare this to Rust’s internal trait <code>Add</code>. If a type implements <code>Add</code>, then we are able to use the operator <code>+</code> to connect instances of it: <code>a + b</code>. For sine though there is no internal way of stating something like “the type is Sine-able”. With the above trait we have added exactly this.</p><p id="9e88">Now, we can implement the two versions of our utility function plus the matrix version:</p>
<figure id="fab8">
<div>
<div>
<iframe class="gist-iframe" src="/gist/rust-play/f6d78613930c78ee7d4c348a7bc7dd01.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><p id="36c3">Okay, runs as well!</p><p id="1997">One thing deems interesting to point out here. If a consumer includes our <code>Utils</code> as a module (say <code>mod utils</code>), none of both versions will be available on <code>Utils</code> without not doing a <code>use utils::Sin</code>. That is, the trait must be brought into context before being able to use it. This sounds cumbersome but adds very much security to our code! Assume, there is another declaration of <code>Sin</code> from another module. This way, you can be certain which one is being used in your code.</p><p id="9cfb">A second very neat thing Rust’s compiler is doing, it only adds those implementations to the final machine code that are actually used. So, if our consumer only uses <code>Sin</code> on <code>Vec<f64></code>, only the corresponding <code>Sin<f64></code> implementation is compiled.</p><p id="ddb2">Looking at the above code, beside all this advertisement of Rust, some might (hopefully) started complaining about the code replication. This <code>impl</code> for <code>Sin<f32></code> and <code>Sin<f64></code> structurally look the same. Of course, from a compilers way of looking at this and even from the runtime, these things are totally different (bit-level). Let us see next how Rust helps out here as well.</p><h2 id="1d35">Avoiding code replication:</h2><p id="f7c3">From a security point of view to writ
Options
e both versions for <code>Sin<f32></code> and <code>Sin<f64></code> looks correctly. From a developers perspective it looks bad since it introduces harder to maintain code. So, we could sum-up: On the one hand we want to have both implementations in the code but only want to write it once. Here comes Rust’s <code>Macros</code> into play that allows to make the compiler writing code for us. Let us see how this works:</p>
<figure id="459e">
<div>
<div>
<iframe class="gist-iframe" src="/gist/rust-play/47f07f8b0f07f54075eeefaa0a4cab75.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><p id="27c7">All the <code>impl</code> have been replaced by the macro definition <code>sin_impl_macro</code> and further four application of it <code>sin_impl_macro!…</code>. The macro itself consists of two parts:</p><p id="a145">The one that provides implementations for <code>Sin<T></code> and <code>T</code> being either <code>f32</code> or <code>f64</code>,</p>
<figure id="680a">
<div>
<div>
<iframe class="gist-iframe" src="/gist/rust-play/a17f93df307012b142b77e3e79e27e42.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><p id="7abe">And the other providing implementations for <code>Sin<Vec<T>></code>,</p>
<figure id="2362">
<div>
<div>
<iframe class="gist-iframe" src="/gist/rust-play/720e84ba7f248728f65a298ea83b10ab.js" allowfullscreen="" frameborder="0" height="undefined" width="undefined">
</div>
</div>
</figure></iframe></div></div></figure><p id="10d5">As you can see, the code inside does only abstracts the use of the type variable <code>T</code>. The rest of both implementations are exactly the once as before.</p><p id="c04e">Also, interesting is, we have here another sort of ‘overloading’. The macro when applied is matching the patterns supplied in the arms. That is,</p><div id="4b2f"><pre>sin_impl_macro!(f32);</pre></div><div id="725a"><pre>sin_impl_macro!(f64);</pre></div><p id="2670">are matched with <code>($T:tt) => …</code></p><p id="f571">and</p><div id="7ef1"><pre>sin_impl_macro!(<span class="hljs-type">Vec</span><<span class="hljs-type">f32</span>>);</pre></div><div id="ea62"><pre>sin_impl_macro!(<span class="hljs-type">Vec</span><<span class="hljs-type">f64</span>>);</pre></div><p id="9b2c">with <code>(Vec<$T:tt>) => …</code></p><p id="9b93">I think we can be satisfied with the final product. Of course, macros are a nice help, but one should not overdo things with it. It can quickly become hard to understand. But let me mention, debugging works as before, since at the end, a macro is just writing code at compile time. Nothing else!</p><p id="0d98">Thanks for reading!</p></article></body>