The Missing Call-Assign Operator
Tags: programminglanguages
Published: 2022-06-26 16:48:41

---
title: The Missing Call-Assign Operator
published: true
date: 2022-06-25 12:30:00 UTC
tags: ProgrammingLanguages
canonical_url: https://kevincox.ca/2022/06/25/call-assign-operator/
---

<main style="--width:min(36em,100%);display:grid;grid-template-columns:1fr var(--width) 1fr;overflow:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;padding:0"><p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">Let’s say you have a type for a Cartesian coordinate.</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">struct</span> <span style="margin:0;box-sizing:border-box;padding:0">Point</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#999">{</span> <span style="margin:0;box-sizing:border-box;padding:0">x</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">:</span> <span style="margin:0;box-sizing:border-box;padding:0">f64</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">,</span> <span style="margin:0;box-sizing:border-box;padding:0">y</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">:</span> <span style="margin:0;box-sizing:border-box;padding:0">f64</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#999">}</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">Now we want to add a method to rotate it. There are two common patterns here:</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">impl</span> <span style="margin:0;box-sizing:border-box;padding:0">Point</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#999">{</span>
	<span style="margin:0;box-sizing:border-box;padding:0;color:#ccc;font-style:italic;white-space:pre-wrap">// Return a new point, don't modify the self parameter.</span>
	<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">fn</span> <span style="margin:0;box-sizing:border-box;padding:0">rotate_new</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">&amp;</span><span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">self</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">,</span> <span style="margin:0;box-sizing:border-box;padding:0">rad</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">:</span> <span style="margin:0;box-sizing:border-box;padding:0">f64</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">)</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">-&gt;</span> <span style="margin:0;box-sizing:border-box;padding:0">Point</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">;</span>

	<span style="margin:0;box-sizing:border-box;padding:0;color:#ccc;font-style:italic;white-space:pre-wrap">// Modify self.</span>
	<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">fn</span> <span style="margin:0;box-sizing:border-box;padding:0">rotate_self</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">&amp;</span><span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">mut</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">self</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">,</span> <span style="margin:0;box-sizing:border-box;padding:0">rad</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">:</span> <span style="margin:0;box-sizing:border-box;padding:0">f64</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#999">}</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">Both of these are quite reasonable, but they are both inconvenient in some situations.</p>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">For example with the <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">rotate_new</code> variant:</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0;color:#ccc;font-style:italic;white-space:pre-wrap">// Creating a new value is easy.</span>
<span style="margin:0;box-sizing:border-box;padding:0">turn_to</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">angle</span><span style="margin:0;box-sizing:border-box;padding:0">.rotate_new</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">amount</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">));</span>

<span style="margin:0;box-sizing:border-box;padding:0;color:#ccc;font-style:italic;white-space:pre-wrap">// But modifying a variable creates duplication.</span>
<span style="margin:0;box-sizing:border-box;padding:0">angle</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">angle</span><span style="margin:0;box-sizing:border-box;padding:0">.rotate_new</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">amount</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">And for the <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">rotate_self</code> variant:</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0;color:#ccc;font-style:italic;white-space:pre-wrap">// Creating a new value is very annoying.</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">let</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">mut</span> <span style="margin:0;box-sizing:border-box;padding:0">target</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">angle</span><span style="margin:0;box-sizing:border-box;padding:0">.clone</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">();</span>
<span style="margin:0;box-sizing:border-box;padding:0">target</span><span style="margin:0;box-sizing:border-box;padding:0">.rotate_self</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">amount</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
<span style="margin:0;box-sizing:border-box;padding:0">turn_to</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">target</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>

<span style="margin:0;box-sizing:border-box;padding:0;color:#ccc;font-style:italic;white-space:pre-wrap">// But modifying a variable is natural.</span>
<span style="margin:0;box-sizing:border-box;padding:0">angle</span><span style="margin:0;box-sizing:border-box;padding:0">.rotate_self</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">amount</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">You can say that mutation is evil so <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">rotate_new</code> is better but in a language that isn’t purely functional you will want to mutate <em style="margin:0;box-sizing:border-box">some</em> things. Additionally, in some cases the extra copying can be prohibitively expensive.</p>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">So how do we define an interface that satisfies all use cases? The simplest solution is to define both like we did above. However, probably with a better naming scheme. How about <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">rotate</code> and <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">rotate_new</code>, <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">rotate</code> and <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">with_rotation</code>? Or we can get cute and call them <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">rotate</code> and <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">rotated</code>? This works, but it requires lots of repetitive code in the interface. Furthermore, the lack of strong naming convention makes users of the library guess what the methods are called.</p>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">Are there any other options? It turns out that programming languages have solved this already! Think about the <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">+</code> operator.</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0">turn</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">angle</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">+</span> <span style="margin:0;box-sizing:border-box;padding:0">adjustment</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
<span style="margin:0;box-sizing:border-box;padding:0">angle</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">+=</span> <span style="margin:0;box-sizing:border-box;padding:0">adjustment</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">;</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">Ok, not just the <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">+</code> operator, but also the <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">+=</code> operator. With these two we can handle both cases naturally! Luckily for us, it isn’t just <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">+</code> that has <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">+=</code>. Depending on your language you probably have op-assign operators for most operators in your language! <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">-=</code>, <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">&lt;&lt;=</code>, <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">||=</code>…</p>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">But it is (usually) a fixed list of operators with implied meaning. Your users probably wouldn’t appreciate if you overloaded <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">&lt;&lt;</code> to rotate a point just because you wanted to take advantage of <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">&lt;&lt;=</code>!</p>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">What if we could have an op-assign operator for function calls? A call-assign operator. The syntax would need to be a little different because we need to put a function name in there, but I think we can find something that doesn’t look too weird.</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0">angle</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">.=</span><span style="margin:0;box-sizing:border-box;padding:0">rotate</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">amount</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
<span style="margin:0;box-sizing:border-box;padding:0">angle</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">.=</span> <span style="margin:0;box-sizing:border-box;padding:0">rotate</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">amount</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
<span style="margin:0;box-sizing:border-box;padding:0">angle</span><span style="margin:0;box-sizing:border-box;padding:0">.rotate</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">amount</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">Take your pick. While <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">.=</code> most closely resembles the other op-assign operators, I like <code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff">thing.method=(...)</code> the most. However in many languages it assigns a parenthesized expression to a property already, so it may not be the best choice overall.</p>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">One place where I think this could come in handy is the <a href="https://www.sohamkamani.com/javascript/builder-pattern/" style="margin:0;box-sizing:border-box;text-decoration:underline;-webkit-text-decoration-color:grey;text-decoration-color:grey">builder pattern</a>. The builder pattern is a way to emulate keyword and optional arguments in languages that don’t have them.</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">let</span> <span style="margin:0;box-sizing:border-box;padding:0">http</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">reqwest</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Client</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">()</span>
	<span style="margin:0;box-sizing:border-box;padding:0">.connect_timeout</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">std</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">time</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Duration</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">from_secs</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#ffb433">1</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">))</span>
	<span style="margin:0;box-sizing:border-box;padding:0">.timeout</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">std</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">time</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Duration</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">from_secs</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#ffb433">10</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">))</span>
	<span style="margin:0;box-sizing:border-box;padding:0">.build</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">()</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">?</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">;</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">Personally, I find this pattern annoying. It works well in the “happy path” but falls apart if you need to sometimes set an option.</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">let</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">mut</span> <span style="margin:0;box-sizing:border-box;padding:0">builder</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">reqwest</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Client</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">()</span>
	<span style="margin:0;box-sizing:border-box;padding:0">.connect_timeout</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">std</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">time</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Duration</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">from_secs</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#ffb433">1</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">))</span>
	<span style="margin:0;box-sizing:border-box;padding:0">.timeout</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">std</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">time</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Duration</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">from_secs</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#ffb433">10</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">));</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">if</span> <span style="margin:0;box-sizing:border-box;padding:0">cfg</span><span style="margin:0;box-sizing:border-box;padding:0">.use_rustls</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#999">{</span>
	<span style="margin:0;box-sizing:border-box;padding:0">builder</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.use_rustls_tls</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">();</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#999">}</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">let</span> <span style="margin:0;box-sizing:border-box;padding:0">http</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.build</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">()</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">?</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">;</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">Once you run into something like this—where you have a conditional or want to delegate some options to another function—I find that the simple mutable approach (<code style="margin:0;box-sizing:border-box;white-space:pre-wrap;padding:.1em;border-radius:.3em;background:#000;border:1px solid #555;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">&amp;</span><span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">mut</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">self</span></code>)ends up simpler and more consistent.</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0;color:#ccc;font-style:italic;white-space:pre-wrap">// Assuming the API was changed.</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">let</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">mut</span> <span style="margin:0;box-sizing:border-box;padding:0">builder</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">reqwest</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Client</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">();</span>
<span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.connect_timeout</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">std</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">time</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Duration</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">from_secs</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#ffb433">1</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">))</span>
<span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.timeout</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">std</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">time</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Duration</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">from_secs</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#ffb433">10</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">));</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">if</span> <span style="margin:0;box-sizing:border-box;padding:0">cfg</span><span style="margin:0;box-sizing:border-box;padding:0">.use_rustls</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#999">{</span>
	<span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.use_rustls_tls</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">();</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#999">}</span>
<span style="margin:0;box-sizing:border-box;padding:0">configure_client</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">&amp;</span><span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">mut</span> <span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">let</span> <span style="margin:0;box-sizing:border-box;padding:0">http</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.build</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">()</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">?</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">;</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">I think call-assign makes this work well with the existing API. This means that users of the “happy path” can continue to use chaining if they prefer. But people like me can use simple assignments.</p>
<div style="box-sizing:border-box;padding:0;grid-column:2;grid-column:1/4;margin:0 0 .8em;display:grid;grid-template-columns:1fr var(--width) 1fr;background:#222;border-top:1px solid #444;border-bottom:1px solid #444;overflow-x:auto"><pre style="box-sizing:border-box;grid-column:2;margin:.4em 1rem"><code style="margin:0;box-sizing:border-box;white-space:pre-wrap;white-space:pre;background:none!important;color:#fff"><span style="margin:0;box-sizing:border-box;padding:0;color:#ccc;font-style:italic;white-space:pre-wrap">// Assuming the API was changed.</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">let</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">mut</span> <span style="margin:0;box-sizing:border-box;padding:0">builder</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">reqwest</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Client</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">();</span>
<span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.connect_timeout</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">std</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">time</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Duration</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">from_secs</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#ffb433">1</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">))</span>
<span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.timeout</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0">std</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">time</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">Duration</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">::</span><span style="margin:0;box-sizing:border-box;padding:0">from_secs</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#ffb433">10</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">));</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">if</span> <span style="margin:0;box-sizing:border-box;padding:0">cfg</span><span style="margin:0;box-sizing:border-box;padding:0">.use_rustls</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#999">{</span>
	<span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.use_rustls_tls</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">();</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#999">}</span>
<span style="margin:0;box-sizing:border-box;padding:0">configure_client</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">(</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">&amp;</span><span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">mut</span> <span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">);</span>
<span style="margin:0;box-sizing:border-box;padding:0;color:#8585e0;font-weight:700">let</span> <span style="margin:0;box-sizing:border-box;padding:0">http</span> <span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">=</span> <span style="margin:0;box-sizing:border-box;padding:0">builder</span><span style="margin:0;box-sizing:border-box;padding:0">.build</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">()</span><span style="margin:0;box-sizing:border-box;padding:0;color:#f5a3a3;font-weight:700">?</span><span style="margin:0;box-sizing:border-box;padding:0;color:#999">;</span>
</code></pre></div>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">(For performance reasons it would make sense to be able to overload call-assign so that it can be implemented more efficiently. But that is just an optimization.)</p>
<p style="box-sizing:border-box;margin:0 1rem .8em;grid-column:2">Are there any languages that support something like this? Do they have mechanisms for optimizing the implementations of call and call-assign separately for where it matters?</p></main>